MWA2APIRepo: properly handle pkgs and icons uploads

This commit is contained in:
Greg Neagle
2017-03-09 16:05:31 -08:00
parent 237a1fa365
commit 5f7dd2fe03

View File

@@ -8,9 +8,10 @@ import plistlib
import subprocess
import tempfile
import urllib2
from xml.parsers.expat import ExpatError
from munkilib.munkirepo import Repo
from munkilib import display
from munkilib.munkirepo import Repo, RepoError
#from munkilib import display
CURL_CMD = '/usr/bin/curl'
@@ -31,14 +32,15 @@ class MWA2APIRepo(Repo):
credentials if needed. For the API repo, well look for a stored
authtoken; if we don't find one, we'll prompt for credentials
and make an authtoken.'''
print 'Please provide credentials for %s:' % self.baseurl
username = raw_input('Username: ')
password = getpass.getpass()
user_and_pass = '%s:%s' % (username, password)
self.authtoken = 'Basic %s' % base64.b64encode(user_and_pass)
if not self.authtoken:
print 'Please provide credentials for %s:' % self.baseurl
username = raw_input('Username: ')
password = getpass.getpass()
user_and_pass = '%s:%s' % (username, password)
self.authtoken = 'Basic %s' % base64.b64encode(user_and_pass)
def _curl(self, relative_url, headers=None, method='GET',
filename=None, content=None):
filename=None, content=None, formdata=None):
'''Use curl to talk to MWA2 API'''
# we use a config/directive file to avoid having the auth header show
# up in a process listing
@@ -53,10 +55,10 @@ class MWA2APIRepo(Repo):
for key in headers:
print >> fileobj, 'header = "%s: %s"' % (key, headers[key])
print >> fileobj, 'header = "Authorization: %s"' % self.authtoken
if method == 'GET':
print >> fileobj, 'header = "Accept: application/xml"'
else:
print >> fileobj, 'header = "Content-type: application/xml"'
if formdata:
for line in formdata:
print >> fileobj, 'form = "%s"' % line
url = os.path.join(self.baseurl, relative_url)
@@ -66,9 +68,9 @@ class MWA2APIRepo(Repo):
cmd = [CURL_CMD, '-q', '--config', directivepath]
if filename and method == 'GET':
cmd.extend(['-o', filename])
if filename and method == 'PUT':
if filename and method in ('PUT', 'POST'):
cmd.extend(['-d', '@%s' % filename])
elif content and method == 'PUT':
elif content and method in ('PUT', 'POST'):
cmd.extend(['-d', content])
#display.display_debug1('Curl command is %s', cmd)
@@ -76,12 +78,15 @@ class MWA2APIRepo(Repo):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate()
fileref = open(directivepath)
curl_directives = fileref.read()
fileref.close()
try:
os.unlink(directivepath)
except OSError:
pass
if proc.returncode:
raise CurlError((proc.returncode, err))
raise CurlError((proc.returncode, err, curl_directives, cmd))
return output
def itemlist(self, kind):
@@ -89,11 +94,15 @@ class MWA2APIRepo(Repo):
Kind might be 'catalogs', 'manifests', 'pkgsinfo', 'pkgs', or 'icons'.
For a file-backed repo this would be a list of pathnames.'''
url = urllib2.quote(kind.encode('UTF-8')) + '?api_fields=filename'
headers = {'Accept': 'application/xml'}
try:
data = self._curl(url)
data = self._curl(url, headers=headers)
except CurlError, err:
raise
plist = plistlib.readPlistFromString(data)
raise RepoError(err)
try:
plist = plistlib.readPlistFromString(data)
except ExpatError, err:
raise RepoError(err)
if kind in ['catalogs', 'manifests', 'pkgsinfo']:
# it's a list of dicts containing 'filename' key/values
return [item['filename'] for item in plist]
@@ -109,10 +118,15 @@ class MWA2APIRepo(Repo):
Avoid using this method with the 'pkgs' kind as it might return a
really large blob of data.'''
url = urllib2.quote(resource_identifier.encode('UTF-8'))
if resource_identifier.startswith(
('catalogs/', 'manifests/', 'pkgsinfo/')):
headers = {'Accept': 'application/xml'}
else:
headers = {}
try:
return self._curl(url)
return self._curl(url, headers=headers)
except CurlError, err:
raise
raise RepoError(err)
def get_to_local_file(self, resource_identifier, local_file_path):
'''Gets the contents of item with given resource_identifier and saves
@@ -122,10 +136,15 @@ class MWA2APIRepo(Repo):
<repo_root>/pkgsinfo/apps/Firefox-52.0.plist to a local file given by
local_file_path.'''
url = urllib2.quote(resource_identifier.encode('UTF-8'))
if resource_identifier.startswith(
('catalogs/', 'manifests/', 'pkgsinfo/')):
headers = {'Accept': 'application/xml'}
else:
headers = {}
try:
result = self._curl(url, filename=local_file_path)
self._curl(url, headers=headers, filename=local_file_path)
except CurlError, err:
raise
raise RepoError(err)
def put(self, resource_identifier, content):
'''Stores content on the repo based on resource_identifier.
@@ -133,10 +152,16 @@ class MWA2APIRepo(Repo):
'pkgsinfo/apps/Firefox-52.0.plist' would result in the content being
saved to <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''
url = urllib2.quote(resource_identifier.encode('UTF-8'))
method = 'PUT'
if resource_identifier.startswith(
('catalogs/', 'manifests/', 'pkgsinfo/')):
headers = {'Content-type': 'application/xml'}
else:
headers = {}
try:
result = self._curl(url, method='PUT', content=content)
self._curl(url, headers=headers, method=method, content=content)
except CurlError, err:
raise
raise RepoError(err)
def put_from_local_file(self, resource_identifier, local_file_path):
'''Copies the content of local_file_path to the repo based on
@@ -144,10 +169,22 @@ class MWA2APIRepo(Repo):
of 'pkgsinfo/apps/Firefox-52.0.plist' would result in the content
being saved to <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''
url = urllib2.quote(resource_identifier.encode('UTF-8'))
try:
result = self._curl(url, method='PUT', filename=local_file_path)
except CurlError, err:
raise
if resource_identifier.startswith(('pkgs/', 'icons/')):
# MWA2API only supports POST for pkgs and icons
# and file uploads need to be form encoded
formdata = ['filedata=@%s' % local_file_path]
try:
self._curl(url, method='POST', formdata=formdata)
except CurlError, err:
raise RepoError(err)
else:
headers = {'Content-type': 'application/xml'}
try:
self._curl(url, headers=headers, method='PUT',
filename=local_file_path)
except CurlError, err:
raise RepoError(err)
def delete(self, resource_identifier):
'''Deletes a repo object located by resource_identifier.
@@ -156,7 +193,7 @@ class MWA2APIRepo(Repo):
<repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''
url = urllib2.quote(resource_identifier.encode('UTF-8'))
try:
result = self._curl(url, method='DELETE')
self._curl(url, method='DELETE')
except CurlError, err:
raise
raise RepoError(err)