Need help adding API PUT method to Python script
Question: I am using the script below to collect inventory information from servers and
send it to a product called Device42. The script currently works however one
of the APIs that I'm trying to add uses PUT instead of POST. I'm not a
programmer and just started using python with this script. This script is
using iron python. Can the PUT method be used in this script?

    
    
    """
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    """
    ##################################################
    # a sample script to show how to use
    #   /api/ip/add-or-update
    #   /api/device/add-or-update
    #
    # requires ironPython (http://ironpython.codeplex.com/) and
    # powershell (http://support.microsoft.com/kb/968929)
    ##################################################
    
    import clr
    
    clr.AddReference('System.Management.Automation')
    
    from System.Management.Automation import (
    PSMethod, RunspaceInvoke
    )
    RUNSPACE = RunspaceInvoke()
    
    import urllib
    import urllib2
    import traceback
    import base64
    import math
    import ssl
    import functools
    BASE_URL='https://device42_URL'
    
    API_DEVICE_URL=BASE_URL+'/api/1.0/devices/'
    API_IP_URL    =BASE_URL+'/api/1.0/ips/'
    API_PART_URL=BASE_URL+'/api/1.0/parts/'
    API_MOUNTPOINT_URL=BASE_URL+'/api/1.0/device/mountpoints/'
    API_CUSTOMFIELD_URL=BASE_URL+'/api/1.0/device/custom_field/'
    
    USER     ='usernme'
    PASSWORD ='password'
    
    old_init = ssl.SSLSocket.__init__
    @functools.wraps(old_init)
    def init_with_tls1(self, *args, **kwargs):
    kwargs['ssl_version'] = ssl.PROTOCOL_TLSv1
    old_init(self, *args, **kwargs)
    ssl.SSLSocket.__init__ = init_with_tls1
    
    def post(url, params):
    """
    http post with basic-auth
    params is dict like object
    """
    try:
        data= urllib.urlencode(params) # convert to ascii chars
        headers = {
            'Authorization' : 'Basic '+ base64.b64encode(USER + ':' + PASSWORD),
            'Content-Type'  : 'application/x-www-form-urlencoded'
        }
    
        req = urllib2.Request(url, data, headers)
    
        print '---REQUEST---',req.get_full_url()
        print req.headers
        print req.data
    
        reponse = urllib2.urlopen(req)
    
        print '---RESPONSE---'
        print reponse.getcode()
        print reponse.info()
        print reponse.read()
    except urllib2.HTTPError as err:
        print '---RESPONSE---'
        print err.getcode()
        print err.info()
        print err.read()
    except urllib2.URLError as err:
        print '---RESPONSE---'
        print err
    
    def to_ascii(s):
        # ignore non-ascii chars
        return s.encode('ascii','ignore')
    
    def wmi(query):
        return [dict([(prop.Name, prop.Value) for prop in psobj.Properties]) for psobj in RUNSPACE.Invoke(query)]
    def closest_memory_assumption(v):
        return int(256 * math.ceil(v / 256.0))
    
    def add_or_update_device():
        computer_system  = wmi('Get-WmiObject Win32_ComputerSystem -Namespace "root\CIMV2"')[0] # take first
        bios             = wmi('Get-WmiObject Win32_BIOS -Namespace "root\CIMV2"')[0]
        operating_system = wmi('Get-WmiObject Win32_OperatingSystem -Namespace "root\CIMV2"')[0]
        environment      = wmi('Get-WmiObject Win32Reg_ESFFarmNode -Namespace "root\CIMV2"')[0]
        mem              = closest_memory_assumption(int(computer_system.get('TotalPhysicalMemory')) / 1047552)
        dev_name         = to_ascii(computer_system.get('Name')).upper()
        fqdn_name        = to_ascii(computer_system.get('Name')).upper() + '.' + to_ascii(computer_system.get('Domain')).lower()
    device = {
        'memory'        : mem,
        'os'            : to_ascii(operating_system.get('Caption')),
        'osver'         : operating_system.get('OSArchitecture'),
        'osmanufacturer': to_ascii(operating_system.get('Manufacturer')),
        'osserial'      : operating_system.get('SerialNumber'),
        'osverno'       : operating_system.get('Version'),
        'service_level' : environment.get('Environment'),
        'notes'         : 'Test w/ Change to Device name collection'
    }
    devicedmn = ''
    for dmn in ['Domain1', 'Domain2', 'Domain3', 'Domain4', 'Domain5']:
        if dmn == to_ascii(computer_system.get('Domain')).strip():
            devicedmn = 'Domain'
            device.update({ 'name' : fqdn_name, })
            break    
    if devicedmn != 'Domain':
        device.update({
            'name': dev_name,
            })
    manufacturer = ''
    for mftr in ['VMware, Inc.', 'Bochs', 'KVM', 'QEMU', 'Microsoft Corporation', 'Xen']:
        if mftr == to_ascii(computer_system.get('Manufacturer')).strip():
            manufacturer = 'virtual'
            device.update({ 'manufacturer' : 'vmware', })
            break    
    if manufacturer != 'virtual':
        device.update({
            'manufacturer': to_ascii(computer_system.get('Manufacturer')).strip(),
            'hardware': to_ascii(computer_system.get('Model')).strip(),
            'serial_no': to_ascii(bios.get('SerialNumber')).strip(),
            'type': 'Physical',
            })    
    cpucount = 0
    for cpu in wmi('Get-WmiObject Win32_Processor  -Namespace "root\CIMV2"'):
        cpucount += 1
        cpuspeed = cpu.get('MaxClockSpeed')
        cpucores = cpu.get('NumberOfCores')
    if cpucount > 0:
    
        device.update({
            'cpucount': cpucount,
            'cpupower': cpuspeed,
            'cpucore':  cpucores,
            })
    hddcount = 0
    hddsize = 0
    for hdd in wmi('Get-WmiObject Win32_LogicalDisk  -Namespace "root\CIMV2" | where{$_.Size -gt 1}'):
        hddcount += 1
        hddsize += hdd.get('Size') / 1073741742
    if hddcount > 0:
    
        device.update({
            'hddcount': hddcount,
            'hddsize': hddsize,
            })
    post(API_DEVICE_URL, device)
    
    for hdd in wmi('Get-WmiObject Win32_LogicalDisk  -Namespace "root\CIMV2" | where{$_.Size -gt 1}'):
        mountpoint = {
              'mountpoint' : hdd.get('Name'),
              'label' : hdd.get('Caption'),
              'fstype' : hdd.get('FileSystem'),
              'capacity' : hdd.get('Size') / 1024 / 1024,
              'free_capacity' : hdd.get('FreeSpace') / 1024 / 1024,
              'device' : dev_name,
              'assignment' : 'Device',
        }
        post(API_MOUNTPOINT_URL, mountpoint)
    
    network_adapter_configuration = wmi('Get-WmiObject Win32_NetworkAdapterConfiguration -Namespace "root\CIMV2" | where{$_.IPEnabled -eq "True"}')
    
    for ntwk in network_adapter_configuration:
        for ipaddr in ntwk.get('IPAddress'):
            ip = {
                'ipaddress'  : ipaddr,
                'macaddress' : ntwk.get('MACAddress'),
                'label'      : ntwk.get('Description'),
                'device'     : dev_name,
            }
            post(API_IP_URL, ip)
    
    def main():
        try:
            add_or_update_device()
        except:
            traceback.print_exc()
    
    if __name__ == "__main__":
        main()
    


Answer: Ok first things first you need to understand the difference between PUT and
POST. I would write it out but another member of the community gave a very
good description of the two
[here](http://stackoverflow.com/questions/107390/whats-the-difference-between-
a-post-and-a-put-http-request).

Now, yes you can use requests with that script. Here is an example of using
the requests library by python, in order to install requests if you have pip
installed install it like this:

    
    
    pip install requests
    

Now, lest go through some examples of using the Requests library, the
documentation can be found [here](http://docs.python-requests.org/en/master/).

HTTP Get Request. So for this example, you call the get function from the
request library, give the url as parameter, then you can print out the text
from the touple that is returned. Since GET will return something, it will
generally be in the text portion of the touple allowing you to print it.

    
    
    r = requests.get('http://urlhere.com/apistuffhere')
    print(r.text)
    

HTTP POST: Posting to a url, depending on how the API was set up will return
something, it generally does for error handling, but you also have to pass in
parameters. Here is an example for a POST request to a new user entry. And
again, you can print the text from the touple to check the response from the
API

    
    
    payload = {'username': 'myloginname', 'password': 'passwordhere'}
    r = requests.post('https://testlogin.com/newuserEntry', params=payload)
    print(r.text)
    

Alternatively you can print just r and it should return you a response 200
which should be successful.

For PUT: You have to keep in mind put responses can not be cacheable, so you
can post data to the PUT url, but you will not know if there is an error or
not but use the same syntax as POST. I have not tried to print out the text
response in a PUT request using the Request library as I don't use PUT in any
API I write.

    
    
    requests.put('http://urlhere.com/putextension')
    

Now for implementing this into your code, you already have the base of the
url, in your post for the login just do:

    
    
    payload = {'username': USERNAME, 'passwd':PASSWORD}
    r = requests.post('https://loginurlhere.com/', params=payload)
    #check response by printing text
    print (r.text)
    

As for putting data to an extension of your api, let us assume you already
have a payload variable ready with the info you need, for example the API
device extension:

    
    
    requests.put(API_DEVICE, params=payload)
    

And that should PUT to the url. If you have any questions comment below and I
can answer them if you would like.

