Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Unified Diff: boto/utils.py

Issue 8386013: Merging in latest boto. (Closed) Base URL: svn://svn.chromium.org/boto
Patch Set: Redoing vendor drop by deleting and then merging. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « boto/tests/test_sqsconnection.py ('k') | boto/vpc/__init__.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: boto/utils.py
diff --git a/boto/utils.py b/boto/utils.py
index 6bad25d2e9db46144c3338978347d8f451c5c808..9a4ff31774cfc105d7fb18bda7085e886a38abed 100644
--- a/boto/utils.py
+++ b/boto/utils.py
@@ -54,6 +54,8 @@ from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders
+import gzip
+
try:
import hashlib
@@ -149,12 +151,15 @@ def get_aws_metadata(headers, provider=None):
for hkey in headers.keys():
if hkey.lower().startswith(metadata_prefix):
val = urllib.unquote_plus(headers[hkey])
- metadata[hkey[len(metadata_prefix):]] = unicode(val, 'utf-8')
+ try:
+ metadata[hkey[len(metadata_prefix):]] = unicode(val, 'utf-8')
+ except UnicodeDecodeError:
+ metadata[hkey[len(metadata_prefix):]] = val
del headers[hkey]
return metadata
-def retry_url(url, retry_on_404=True):
- for i in range(0, 10):
+def retry_url(url, retry_on_404=True, num_retries=10):
+ for i in range(0, num_retries):
try:
req = urllib2.Request(url)
resp = urllib2.urlopen(req)
@@ -196,7 +201,7 @@ def _get_instance_metadata(url):
d[key] = val
return d
-def get_instance_metadata(version='latest'):
+def get_instance_metadata(version='latest', url='http://169.254.169.254'):
"""
Returns the instance metadata as a nested Python dictionary.
Simple values (e.g. local_hostname, hostname, etc.) will be
@@ -204,12 +209,12 @@ def get_instance_metadata(version='latest'):
be stored in the dict as a list of string values. More complex
fields such as public-keys and will be stored as nested dicts.
"""
- url = 'http://169.254.169.254/%s/meta-data/' % version
- return _get_instance_metadata(url)
+ return _get_instance_metadata('%s/%s/meta-data/' % (url, version))
-def get_instance_userdata(version='latest', sep=None):
- url = 'http://169.254.169.254/%s/user-data' % version
- user_data = retry_url(url, retry_on_404=False)
+def get_instance_userdata(version='latest', sep=None,
+ url='http://169.254.169.254'):
+ ud_url = '%s/%s/user-data' % (url,version)
+ user_data = retry_url(ud_url, retry_on_404=False)
if user_data:
if sep:
l = user_data.split(sep)
@@ -220,6 +225,7 @@ def get_instance_userdata(version='latest', sep=None):
return user_data
ISO8601 = '%Y-%m-%dT%H:%M:%SZ'
+ISO8601_MS = '%Y-%m-%dT%H:%M:%S.%fZ'
def get_ts(ts=None):
if not ts:
@@ -227,7 +233,12 @@ def get_ts(ts=None):
return time.strftime(ISO8601, ts)
def parse_ts(ts):
- return datetime.datetime.strptime(ts, ISO8601)
+ try:
+ dt = datetime.datetime.strptime(ts, ISO8601)
+ return dt
+ except ValueError:
+ dt = datetime.datetime.strptime(ts, ISO8601_MS)
+ return dt
def find_class(module_name, class_name=None):
if class_name:
@@ -502,16 +513,20 @@ class LRUCache(dict):
class Password(object):
"""
- Password object that stores itself as SHA512 hashed.
+ Password object that stores itself as hashed.
+ Hash defaults to SHA512 if available, MD5 otherwise.
"""
- def __init__(self, str=None):
+ hashfunc=_hashfn
+ def __init__(self, str=None, hashfunc=None):
"""
- Load the string from an initial value, this should be the raw SHA512 hashed password
+ Load the string from an initial value, this should be the raw hashed password.
"""
self.str = str
+ if hashfunc:
+ self.hashfunc = hashfunc
def set(self, value):
- self.str = _hashfn(value).hexdigest()
+ self.str = self.hashfunc(value).hexdigest()
def __str__(self):
return str(self.str)
@@ -519,7 +534,7 @@ class Password(object):
def __eq__(self, other):
if other == None:
return False
- return str(_hashfn(other).hexdigest()) == str(self.str)
+ return str(self.hashfunc(other).hexdigest()) == str(self.str)
def __len__(self):
if self.str:
@@ -527,7 +542,8 @@ class Password(object):
else:
return 0
-def notify(subject, body=None, html_body=None, to_string=None, attachments=[], append_instance_id=True):
+def notify(subject, body=None, html_body=None, to_string=None, attachments=None, append_instance_id=True):
+ attachments = attachments or []
if append_instance_id:
subject = "[%s] %s" % (boto.config.get_value("Instance", "instance-id"), subject)
if not to_string:
@@ -603,5 +619,73 @@ def pythonize_name(name, sep='_'):
s += c
return s
-def awsify_name(name):
- return name[0:1].upper()+name[1:]
+def write_mime_multipart(content, compress=False, deftype='text/plain', delimiter=':'):
+ """Description:
+ :param content: A list of tuples of name-content pairs. This is used
+ instead of a dict to ensure that scripts run in order
+ :type list of tuples:
+
+ :param compress: Use gzip to compress the scripts, defaults to no compression
+ :type bool:
+
+ :param deftype: The type that should be assumed if nothing else can be figured out
+ :type str:
+
+ :param delimiter: mime delimiter
+ :type str:
+
+ :return: Final mime multipart
+ :rtype: str:
+ """
+ wrapper = MIMEMultipart()
+ for name,con in content:
+ definite_type = guess_mime_type(con, deftype)
+ maintype, subtype = definite_type.split('/', 1)
+ if maintype == 'text':
+ mime_con = MIMEText(con, _subtype=subtype)
+ else:
+ mime_con = MIMEBase(maintype, subtype)
+ mime_con.set_payload(con)
+ # Encode the payload using Base64
+ Encoders.encode_base64(mime_con)
+ mime_con.add_header('Content-Disposition', 'attachment', filename=name)
+ wrapper.attach(mime_con)
+ rcontent = wrapper.as_string()
+
+ if compress:
+ buf = StringIO.StringIO()
+ gz = gzip.GzipFile(mode='wb', fileobj=buf)
+ try:
+ gz.write(rcontent)
+ finally:
+ gz.close()
+ rcontent = buf.getvalue()
+
+ return rcontent
+
+def guess_mime_type(content, deftype):
+ """Description: Guess the mime type of a block of text
+ :param content: content we're finding the type of
+ :type str:
+
+ :param deftype: Default mime type
+ :type str:
+
+ :rtype: <type>:
+ :return: <description>
+ """
+ #Mappings recognized by cloudinit
+ starts_with_mappings={
+ '#include' : 'text/x-include-url',
+ '#!' : 'text/x-shellscript',
+ '#cloud-config' : 'text/cloud-config',
+ '#upstart-job' : 'text/upstart-job',
+ '#part-handler' : 'text/part-handler',
+ '#cloud-boothook' : 'text/cloud-boothook'
+ }
+ rtype = deftype
+ for possible_type,mimetype in starts_with_mappings.items():
+ if content.startswith(possible_type):
+ rtype = mimetype
+ break
+ return(rtype)
« no previous file with comments | « boto/tests/test_sqsconnection.py ('k') | boto/vpc/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698