如何使用urllib2.urlopen将检索到的二进制plist操作为可读的xml plist而不使用Python在本地保存文件?

时间:2014-06-12 15:57:20

标签: python

我们使用Python脚本与Deploy Studio服务器通信,以使用Deploy Studio的Web访问URL自动更新用户和计算机信息。由于最近的更改,他们现在以二进制plist格式存储计算机的Plists,而不是XML。

以下是目前适用于旧版DS的内容(来源:http://macops.ca/interfacing-with-deploystudio-using-http/):

#!/usr/bin/python

import urllib2
import plistlib
from random import randrange

host = 'https://my.ds.repo:60443'
adminuser = 'testdsuser'
adminpass = '12345'


def setupAuth():
    """Install an HTTP Basic Authorization header globally so it's used for
every request."""
    auth_handler = urllib2.HTTPBasicAuthHandler()
    auth_handler.add_password(realm='DeployStudioServer',
                              uri=host,
                              user=adminuser,
                              passwd=adminpass)
    opener = urllib2.build_opener(auth_handler)
    urllib2.install_opener(opener)


def getHostData(machine_id):
    """Return the full plist for a computer entry"""
    machine_data = urllib2.urlopen(host + '/computers/get/entry?id=%s' % machine_id)
    plist = plistlib.readPlistFromString(machine_data.read())
    # if id isn't found, result will be an empty plist
    return plist


def updateHostProperties(machine_id, properties, key_mac_addr=False, create_new=False):
    """Update the computer at machine_id with properties, a dict of properties and
values we want to set with new values. Return the full addinfourl object or None
if we found no computer to update and we aren't creating a new one. Set create_new
to True in order to enable creating new entries."""
    found_comp = getHostData(machine_id)

    # If we found no computer and we don't want a new record created
    if not found_comp and not create_new:
        return None

    new_data = {}
    if found_comp:
        # Computer data comes back as plist nested like: {'SERIALNO': {'cn': 'my-name'}}
        # DeployStudioServer expects a /set/entry POST like: {'cn': 'my-new-name'}
        # so we copy the keys up a level
        update = dict((k, v) for (k, v) in found_comp[machine_id].items())
        new_data = update.copy()
    else:
        # No computer exists for this ID, we need to set up two required keys:
        # 'dstudio-host-primary-key' and one of 'dstudio-host-serial-number'
        # or 'dstudio-mac-addr' is required, otherwise request is ignored
        # - IOW: you can't only rely on status codes
        # - primary key is a server-level config, but we seem to need this per-host
        if key_mac_addr:
            new_data['dstudio-host-primary-key'] = 'dstudio-mac-addr'
        else:
            new_data['dstudio-host-primary-key'] = 'dstudio-host-serial-number'
        new_data[new_data['dstudio-host-primary-key']] = machine_id

    for (k, v) in properties.items():
        new_data[k] = v
    plist_to_post = plistlib.writePlistToString(new_data)
    result = urllib2.urlopen(host + '/computers/set/entry?id=' + machine_id,
                            plist_to_post)
    return result


def main():
    setupAuth()

    # Update HOWSANNIE with a new computer name (assuming this entry already exists)
    random_name = 'random-id-' + str(randrange(100))
    result = updateHostProperties('HOWSANNIE', {'cn': random_name,
                                            'dstudio-hostname': random_name})

    # Update DOUGLASFIRS with a new computername and custom properties, or create
    # it if it doesn't already exist
    random_name = 'random-id-' + str(randrange(100))
    updateHostProperties('DOUGLASFIRS',
                    {'cn': random_name,
                    'dstudio-hostname': random_name,
                    'dstudio-custom-properties': [{
                        'dstudio-custom-property-key': 'ASSET_TAG',
                        'dstudio-custom-property-label': 'My Great Asset Tag',
                        'dstudio-custom-property-value': 'BL4CKL0DG3'}]
                    },
                    create_new=True)

if __name__ == "__main__":
    main()

我们将此与本土Web界面结合使用,技术人员可在重新映像计算机时输入信息并自动更新DS数据库中的信息。

我尝试使用biplist这样的库无济于事。我更喜欢不必在服务器上本地存储文件,然后使用bash命令plutil进行转换。无论如何我可以操纵信息存储到的变量吗?在这种情况下,它将是' machine_data'。

我已成功使用带有-o标志的bash命令curl来指示将文件保存为有效的.plist文件,但如前所述,我想这样做而不保存本地文件,如果可能的。

部署可用的Studio Web服务:here

1 个答案:

答案 0 :(得分:1)

将所有@ martijn-pieters评论整合到一个答案中:

pip install biplist

import urllib2
import io
import biplist

sock = urllib2.urlopen('https://cfpropertylist.googlecode.com/svn/trunk/examples/sample.binary.plist' )
buf = io.BytesIO(sock.read())
xml = biplist.readPlist(buf)
print xml

输出:

  

{'Pets Names':[],'Name':'John Doe','Picture':'< B \ x81 \ xa5 \ x81 \ xa5 \ x99 \ x81B<','出生年份': 1965年,“毕业日期”:datetime.datetime(2004,6,22,19,23,43),“出生之城”:“斯普林菲尔德”,“儿童名字”:['John','Kyra']}