mirror of
https://github.com/munki/munki.git
synced 2026-01-27 01:19:12 -06:00
MWA2APIRepo: properly handle pkgs and icons uploads
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user