[cisco-voip] CUCM Bulk TFTP File Upload

Brian Meade bmeade90 at vt.edu
Mon Jun 4 08:47:35 EDT 2018


Thanks for cleaning that up Anthony!

My main goal with this is to bulk upload entire directories and all the
sub-directories so I can easily upload all the Desktops directories and
such.

Since I'm bulk uploading so many files, I decided to just do a single node
at a time but your edit should work fine to make this multi-node.

Attached my finalized script I was able to use to upload a few hundred
files to a 4-node cluster on Friday.

On Sat, Jun 2, 2018 at 3:19 PM, Anthony Holloway <
avholloway+cisco-voip at gmail.com> wrote:

> Here's your code re-worked a little Brian, for you or for anyone else, and
> I tested it on 11.5 and it works.  I did not put in any error handling, so
> I'll leave that up to you.  You can do things like Try/Catch or checking
> for resp.status_code == 200, file existence checking, etc.  I figure,
> knowing how to make it work was the challenge, not error handling, so I
> left that out.
>
> # Install Python 2.7 and choose the option to add to path (off by default)
> # Then install two modules
> #  C:\>pip install requests
> #  C:\>pip install BeautifulSoup
> # Then run the program
> #  C:\>python tftp.py
>
> import requests
> from BeautifulSoup import BeautifulSoup
> requests.packages.urllib3.disable_warnings()
>
> tftp_host = ""
> tftp_user = ""
> tftp_pass = ""
> tftp_file = ""
> tftp_path = ""
>
> url_base = "https://{}/cmplatform/".format(tftp_host)
> url_login = "{}j_security_check".format(url_base)
> url_upload = "{}tftpFileUpload.do".format(url_base)
>
> # Allows us to keep track of our login session
> print "\nLogging in to {}...".format(tftp_host),
> connection = requests.Session()
>
> # Start a new session by simply access a page on the server
> resp = connection.get(url_base, verify = False)
>
> # Our login form data
> form_data = {
> "appNav": "cmplatform",
> "j_username": tftp_user,
> "j_password": tftp_pass
> }
>
> # Our login submission to the server
> resp = connection.post(url_login, verify = False, data = form_data)
> print "Success!\n"
>
> # We need to grab the token the server gives us, so we can pass it back
> upon upload
> print "Grabbing a new token...",
> soup = BeautifulSoup(connection.get(url_upload, verify = False).content)
>
> # It's a hidden input element on the upload form with the name of "token"
> token = soup.find("input", {"name": "token"}).get("value")
> print "Found! [{}]\n".format(token)
>
> # Our upload form submission data
> payload = {
> "struts.token.name": (None, "token"),
> "token": (None, token),
> "file": (tftp_file, open(tftp_file, "rb"), {"Content-Type": "text/plain"}),
> "directory": (None, tftp_path)
> }
>
> # Our upload submission to the server
> print "Uploading file: {}...".format(tftp_file),
> resp = connection.post(url_upload, verify = False, files = payload)
> print "Success!\n"
>
> print "Done!"
>
> If you want multiple server/multiple file support, it's really just a
> small modification (highlighted in red):
>
> # Install Python 2.7 and choose the option to add to path (off by default)
> # Then install two modules
> #  C:\>pip install requests
> #  C:\>pip install BeautifulSoup
> # Then run the program
> #  C:\>python tftp.py
>
> import requests
> from BeautifulSoup import BeautifulSoup
> requests.packages.urllib3.disable_warnings()
>
> tftp_hosts = [
> "host1",
> "hostN"
> ]
> tftp_user = ""
> tftp_pass = ""
>
> tftp_files = [
> "file1",
> "fileN"
> ]
> tftp_path = ""
>
> for tftp_host in tftp_hosts:
>
> url_base = "https://{}/cmplatform/".format(tftp_host)
> url_login = "{}j_security_check".format(url_base)
> url_upload = "{}tftpFileUpload.do".format(url_base)
>
> # Allows us to keep track of our login session
> print "\nLogging in to {}...".format(tftp_host),
> connection = requests.Session()
>
> # Start a new session by simply access a page on the server
> resp = connection.get(url_base, verify = False)
>
> # Our login form data
> form_data = {
> "appNav": "cmplatform",
> "j_username": tftp_user,
> "j_password": tftp_pass
> }
>
> # Our login submission to the server
> resp = connection.post(url_login, verify = False, data = form_data)
> print "Success!\n"
> for tftp_file in tftp_files:
>
> # We need to grab the token the server gives us, so we can pass it back
> upon upload
> print "Grabbing a new token...",
> soup = BeautifulSoup(connection.get(url_upload, verify = False).content)
>
> # It's a hidden input element on the upload form with the name of "token"
> token = soup.find("input", {"name": "token"}).get("value")
> print "Found! [{}]\n".format(token)
>
> # Our upload form submission data
> payload = {
> "struts.token.name": (None, "token"),
> "token": (None, token),
> "file": (tftp_file, open(tftp_file, "rb"), {"Content-Type": "text/plain"}),
> "directory": (None, tftp_path)
> }
>
> # Our upload submission to the server
> print "Uploading file: {}...".format(tftp_file),
> resp = connection.post(url_upload, verify = False, files = payload)
> print "Success!\n"
>
> print "Done!"
>
> On Fri, Jun 1, 2018 at 3:38 PM Brian Meade <bmeade90 at vt.edu> wrote:
>
>> So just re-read through everything and sure enough I was sending to the
>> wrong IP when running the script.  No wonder it's shown as uploading
>> successfully the entire time.
>>
>> Thanks for you and Stephen's assistance!
>>
>> Tommy, BTW you can remove a lot of the manual set headers if you want to
>> clean yours up.  It seems to work without them.
>>
>> Thanks,
>> Brian Meade
>>
>> On Fri, Jun 1, 2018 at 4:10 PM, Schlotterer, Tommy <
>> tschlotterer at presidio.com> wrote:
>>
>>> Just tested on CUCM 11.5, worked just fine.
>>>
>>>
>>>
>>> Thanks
>>>
>>>
>>> Tommy
>>>
>>>
>>>
>>> *From:* bmeade90 at gmail.com [mailto:bmeade90 at gmail.com] *On Behalf Of *Brian
>>> Meade
>>> *Sent:* Friday, June 1, 2018 4:06 PM
>>> *To:* Schlotterer, Tommy <tschlotterer at presidio.com>
>>> *Cc:* cisco-voip voyp list <cisco-voip at puck.nether.net>
>>> *Subject:* Re: [cisco-voip] CUCM Bulk TFTP File Upload
>>>
>>>
>>>
>>> *EXTERNAL EMAIL*
>>>
>>>
>>>
>>>
>>>
>>> Thanks Tommy!
>>>
>>>
>>>
>>> Have you tested against CUCM 11.x okay?
>>>
>>>
>>>
>>> I need to build the dependencies to fully run yours.  I tried pulling
>>> out the important upload code but seeing the same issue I'm having with my
>>> code.
>>>
>>>
>>>
>>> Thanks,
>>>
>>> Brian Meade
>>>
>>>
>>>
>>> On Fri, Jun 1, 2018 at 1:18 PM, Schlotterer, Tommy <
>>> tschlotterer at presidio.com> wrote:
>>>
>>> Brian,
>>>
>>>
>>>
>>> Here is my really hacky python script to do this.
>>>
>>>
>>>
>>> Thanks
>>>
>>>
>>> Tommy
>>>
>>>
>>>
>>> *From:* cisco-voip [mailto:cisco-voip-bounces at puck.nether.net] *On
>>> Behalf Of *Brian Meade
>>> *Sent:* Friday, June 1, 2018 9:54 AM
>>> *To:* cisco-voip voyp list <cisco-voip at puck.nether.net>
>>> *Subject:* [cisco-voip] CUCM Bulk TFTP File Upload
>>>
>>>
>>>
>>> *EXTERNAL EMAIL*
>>>
>>>
>>>
>>>
>>>
>>> Does anyone have a working script for this?
>>>
>>>
>>>
>>> I put together a script in python to do this but hitting some issues.
>>>
>>>
>>>
>>> Right now I’ve got it to the point that it’s trying to upload a single
>>> file.
>>>
>>>
>>>
>>> I used Fiddler to copy what I saw for a working request through a
>>> browser.
>>>
>>>
>>>
>>> I first do a Get to the cmplatform page to get a cookie.
>>>
>>>
>>>
>>> I then do a Post to the /cmplatform/j_security_check page to
>>> authenticate that cookie.
>>>
>>>
>>>
>>> I then do a Get to /cmplatform/tftpFileUpload.do to get a Struts Token.
>>>
>>>
>>>
>>> I then do a Post to /cmplatform/tftpFileUpload.do with the Struts token,
>>> filename, and directory details.
>>>
>>>
>>>
>>> This looks to be successful as I get a "File uploaded successfully"
>>> message returned but then I can't find the file on the TFTP File Management
>>> page.
>>>
>>>
>>>
>>> I tried using the curl methods I found here (
>>> https://communities.cisco.com/docs/DOC-43506 ) but no luck there.  Not
>>> sure if this works in 11.5 without grabbing the Struts token.   Without a
>>> token, I get an error message saying something to the affect of I hit the
>>> Submit button twice.
>>>
>>>
>>>
>>> Here's what it looks like when my script runs in Fiddler:
>>>
>>>
>>>
>>>
>>>
>>> This looks almost exactly like the real example through a browser I
>>> captured minus a few headers I tried manually adding with no luck.
>>>
>>>
>>>
>>> Python script attached.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> * Tommy Schlotterer | Systems Engineer - Collaboration Presidio (NASDAQ:
>>> PSDO) | presidio.com <http://presidio.com> 20 N Saint Clair 3rd Floor,
>>> Toledo, OH 43604
>>> <https://maps.google.com/?q=20+N+Saint+Clair+3rd+Floor,+Toledo,+OH+43604&entry=gmail&source=g>
>>> D: 419.214.1415 <(419)%20214-1415> | C: 419.706.0259 <(419)%20706-0259> |
>>> tschlotterer at presidio.com <tschlotterer at presidio.com>*
>>>
>>>
>>>
>>> * [image: Future. Built.] <http://www.presidio.com>*
>>>
>>>
>>>
>>>
>>> * Follow us: [image: Follow Presidio on Twitter]
>>> <http://www.twitter.com/presidio>*
>>>
>>>
>>>
>>>
>>>
>>> *This message w/attachments (message) is intended solely for the use of
>>> the intended recipient(s) and may contain information that is privileged,
>>> confidential or proprietary. If you are not an intended recipient, please
>>> notify the sender, and then please delete and destroy all copies and
>>> attachments. Please be advised that any review or dissemination of, or the
>>> taking of any action in reliance on, the information contained in or
>>> attached to this message is prohibited.*
>>>
>>>
>>>
>>>
>>>
>>> [image: Future. Built.] <http://www.presidio.com>
>>>
>>>
>>> Follow us:
>>>
>>> [image: Follow Presidio on Twitter] <http://www.twitter.com/presidio>
>>>
>>>
>>>
>>>
>> _______________________________________________
>> cisco-voip mailing list
>> cisco-voip at puck.nether.net
>> https://puck.nether.net/mailman/listinfo/cisco-voip
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://puck.nether.net/pipermail/cisco-voip/attachments/20180604/d538b95d/attachment.html>
-------------- next part --------------
# Install Python 2.7 and choose the option to add to path (off by default)
# Then install two modules
#  C:\>pip install requests
#  C:\>pip install BeautifulSoup
# May need to use "python -m pip install requests"
# Then run the program CUCM-Bulk-TFTP-Upload.py
#  C:\>python tftp.py hostname/IP username password localdirectory
# Windows formatting for local directory- C:\\TFTP-Root\\tftpfiles
# This program will traverse a local directory recursively and upload 
# all files while maintaining the directory structure.
# You can pass in the parameters on the command line or edit the
# sys.argv line at the bottom of the script.

import sys
import requests
from bs4 import BeautifulSoup
import warnings
import os.path
import os

def main(argv):
   warnings.filterwarnings("ignore")
   hostname= ''
   username= ''
   password= ''
   local_file_path= ''
   token= ''
   
   try:
      hostname = sys.argv[1]
      username = sys.argv[2]
      password = sys.argv[3]
      local_file_path = sys.argv[4]
   except:
      print('Please enter hostname/IP Address, username, password, the local file path, and the remote file path')
      sys.exit()
	
   #Create a new session to maintain cookies across requests      
   s = requests.Session()
   
   #Initial Get Request to get a cookie
   getcookie= s.get('https://' + hostname + '/cmplatform', verify=False)
   
   #Post authentication details to authenticate cookie
   payload= {'appNav': 'cmplatform', 'j_username': username, 'j_password': password}
   post= s.post('https://' + hostname + '/cmplatform/j_security_check', data=payload, verify=False)

   #Get request to obtain first Struts Token, use Beautiful Soup to extract token from returned CSS
   tokenrequest= s.get('https://' + hostname + '/cmplatform/tftpFileUpload.do', verify=False)
   soup = BeautifulSoup(tokenrequest.text)
   try:
      token = soup.find('input', {'name': 'token'}).get('value')
   except:
      print('Couldn''t get token.  You may be trying too often.')
      sys.exit()
   
   #For Loops to walk through all files in directory/sub-directories
   for root, dirs, files in os.walk(local_file_path):
      path = root.split(os.sep)
      print((len(path) - 1) * '---', os.path.basename(root))
      for file in files:
         print(len(path) * '---', file)
         fullpath = os.path.join(root, file)
         remote_path = os.path.relpath(root, local_file_path)

         #Needed for Windows file paths
         remote_path = remote_path.replace("\\","/")

         #Upload individual file
         f= open(fullpath, 'rb')
         #Post response will provide the next Struts token
         postfile = s.post('https://' + hostname + '/cmplatform/tftpFileUpload.do', files={'struts.token.name': (None, 'token'),'token': (None, token), 'file': (file,f,'application/octet-stream'), 'directory': (None, remote_path)}, verify = False)
         soup = BeautifulSoup(postfile.text)
         try:
            token = soup.find('input', {'name': 'token'}).get('value')
         except:
            print('Couldn''t get token.  You may be trying too often.')
            sys.exit()
         print('Uploaded file ' + file + ' to ' + remote_path)
         f.close();

   print('Bulk upload completed successfully!')
         
if __name__ == "__main__":
   #Replace the below values or pass the commands through the command-line and remove the below line
   sys.argv = ["CUCM-Bulk-TFTP-Upload.py", "192.168.1.1", "admin", "mypassword", "C:\\TFTP-Root\\tftpfiles"]
   main(sys.argv[1:])


More information about the cisco-voip mailing list