~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to nova/utils.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Monty Taylor, Chuck Short, Joseph Heck
  • Date: 2012-02-24 10:08:10 UTC
  • mfrom: (1.1.46)
  • Revision ID: package-import@ubuntu.com-20120224100810-1wnpdx8c1c43702w
Tags: 2012.1~e4~20120224.12913-0ubuntu1
[ Monty Taylor ]
* Move files from nova/locale to /usr/share/locale

[ Chuck Short ]
* debian/rules: Fix FTBFS.
* debian/control: Add depends on python-babel.
* debian/control: Add depends on python-iso8601.
* debian/nova-api-os-volume.install: Fix FTBS.
* debian/patches/libvirt-use-console-pipe.patch: Refreshed and 
  Re-enabled. (LP: #879666)
* debian/control: Make sure we install nova-cert

[ Joseph Heck ]
* debian/nova-console.install: Add nova-consoleauth.
* Add nova-api-ec2, nova-api-os-compute, and nova-api-os-volume.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import functools
25
25
import hashlib
26
26
import inspect
 
27
import itertools
27
28
import json
28
29
import lockfile
29
30
import os
32
33
import re
33
34
import shlex
34
35
import socket
 
36
import stat
35
37
import struct
36
38
import sys
37
39
import time
44
46
from eventlet import greenthread
45
47
from eventlet import semaphore
46
48
from eventlet.green import subprocess
 
49
import iso8601
47
50
import netaddr
48
51
 
49
52
from nova import exception
52
55
from nova.openstack.common import cfg
53
56
 
54
57
 
 
58
BITS_PER_BYTE = 8
55
59
LOG = logging.getLogger(__name__)
56
 
ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
 
60
ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
57
61
PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
58
62
FLAGS = flags.FLAGS
59
63
 
534
538
 
535
539
 
536
540
def isotime(at=None):
537
 
    """Returns iso formatted utcnow."""
538
 
    return strtime(at, ISO_TIME_FORMAT)
 
541
    """Stringify time in ISO 8601 format"""
 
542
    if not at:
 
543
        at = datetime.datetime.utcnow()
 
544
    str = at.strftime(ISO_TIME_FORMAT)
 
545
    tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC'
 
546
    str += ('Z' if tz == 'UTC' else tz)
 
547
    return str
539
548
 
540
549
 
541
550
def parse_isotime(timestr):
542
551
    """Turn an iso formatted time back into a datetime."""
543
 
    return parse_strtime(timestr, ISO_TIME_FORMAT)
 
552
    try:
 
553
        return iso8601.parse_date(timestr)
 
554
    except (iso8601.ParseError, TypeError) as e:
 
555
        raise ValueError(e.message)
 
556
 
 
557
 
 
558
def normalize_time(timestamp):
 
559
    """Normalize time in arbitrary timezone to UTC"""
 
560
    offset = timestamp.utcoffset()
 
561
    return timestamp.replace(tzinfo=None) - offset if offset else timestamp
544
562
 
545
563
 
546
564
def parse_mailmap(mailmap='.mailmap'):
654
672
def xhtml_escape(value):
655
673
    """Escapes a string so it is valid within XML or XHTML.
656
674
 
657
 
    Code is directly from the utf8 function in
658
 
    http://github.com/facebook/tornado/blob/master/tornado/escape.py
659
 
 
660
675
    """
661
 
    return saxutils.escape(value, {'"': '"'})
 
676
    return saxutils.escape(value, {'"': '"', "'": '''})
662
677
 
663
678
 
664
679
def utf8(value):
697
712
        if test(value):
698
713
            return unicode(value)
699
714
 
 
715
    # value of itertools.count doesn't get caught by inspects
 
716
    # above and results in infinite loop when list(value) is called.
 
717
    if type(value) == itertools.count:
 
718
        return unicode(value)
 
719
 
700
720
    # FIXME(vish): Workaround for LP bug 852095. Without this workaround,
701
721
    #              tests that raise an exception in a mocked method that
702
722
    #              has a @wrap_exception with a notifier will fail. If
1118
1138
    try:
1119
1139
        yield
1120
1140
    except Exception:
1121
 
        LOG.exception(_('Original exception being dropped'),
1122
 
                      exc_info=(type_, value, traceback))
 
1141
        # NOTE(jkoelker): Using LOG.error here since it accepts exc_info
 
1142
        #                 as a kwargs.
 
1143
        LOG.error(_('Original exception being dropped'),
 
1144
                  exc_info=(type_, value, traceback))
1123
1145
        raise
1124
1146
    raise type_, value, traceback
1125
1147
 
1420
1442
        return out
1421
1443
    except exception.ProcessExecutionError:
1422
1444
        raise exception.FileNotFound(file_path=file_path)
 
1445
        
 
1446
class RingBuffer(object):
 
1447
    """Generic userspace on-disk ringbuffer implementation."""
 
1448
    _header_max_int = (2 ** (struct.calcsize('I') * BITS_PER_BYTE)) - 1
 
1449
    _header_format = 'II'
 
1450
    _header_size = struct.calcsize(_header_format)
 
1451
 
 
1452
    def __init__(self, backing_file, max_size=65536):
 
1453
        # We need one extra byte as the buffer is kept with
 
1454
        # one byte free to avoid the head==tail full/empty
 
1455
        # problem
 
1456
        max_size += 1
 
1457
 
 
1458
        if not 0 < max_size <= RingBuffer._header_max_int:
 
1459
            raise ValueError(_('RingBuffer size out of range'))
 
1460
        had_already_existed = os.path.exists(backing_file)
 
1461
        self.f = self._open(backing_file)
 
1462
        if had_already_existed:
 
1463
            file_size = os.fstat(self.f.fileno()).st_size
 
1464
            if file_size:
 
1465
                current_size = file_size - self._header_size
 
1466
                if not 0 < current_size <= RingBuffer._header_max_int:
 
1467
                    self.f.close()
 
1468
                    raise ValueError(_('Disk RingBuffer size out of range'))
 
1469
                self.max_size = current_size
 
1470
 
 
1471
                # If the file doesn't contain a header, assume it is corrupt
 
1472
                # and recreate
 
1473
                if file_size < self._header_size:
 
1474
                    self._write_header(0, 0)  # initialise to empty
 
1475
 
 
1476
                # If head or tail point beyond the file then bomb out
 
1477
                head, tail = self._read_header()
 
1478
                if head >= current_size or tail >= current_size:
 
1479
                    self.f.close()
 
1480
                    raise ValueError(_('RingBuffer %s is corrupt') %
 
1481
                                     backing_file)
 
1482
            else:
 
1483
                # File is zero bytes: treat as new file
 
1484
                self.max_size = max_size
 
1485
                self._initialise_empty_file()
 
1486
        else:
 
1487
            self.max_size = max_size
 
1488
            self._initialise_empty_file()
 
1489
 
 
1490
    def _initialise_empty_file(self):
 
1491
        os.ftruncate(self.f.fileno(), self.max_size + self._header_size)
 
1492
        self._write_header(0, 0)  # head == tail means no data
 
1493
 
 
1494
    @staticmethod
 
1495
    def _open(filename):
 
1496
        """Open a file without truncating it for both reading and writing in
 
1497
        binary mode."""
 
1498
        # Built-in open() cannot open in read/write mode without truncating.
 
1499
        fd = os.open(filename, os.O_RDWR | os.O_CREAT, 0666)
 
1500
        return os.fdopen(fd, 'w+')
 
1501
 
 
1502
    def _read_header(self):
 
1503
        self.f.seek(0)
 
1504
        return struct.unpack(self._header_format,
 
1505
                             self.f.read(self._header_size))
 
1506
 
 
1507
    def _write_header(self, head, tail):
 
1508
        self.f.seek(0)
 
1509
        self.f.write(struct.pack(self._header_format, head, tail))
 
1510
 
 
1511
    def _seek(self, pos):
 
1512
        """Seek to pos in data (ignoring header)."""
 
1513
        self.f.seek(self._header_size + pos)
 
1514
 
 
1515
    def _read_slice(self, start, end):
 
1516
        if start == end:
 
1517
            return ''
 
1518
 
 
1519
        self._seek(start)
 
1520
        return self.f.read(end - start)
 
1521
 
 
1522
    def _write_slice(self, pos, data):
 
1523
        self._seek(pos)
 
1524
        self.f.write(data)
 
1525
 
 
1526
    def peek(self):
 
1527
        """Read the entire ringbuffer without consuming it."""
 
1528
        head, tail = self._read_header()
 
1529
        if head < tail:
 
1530
            # Wraps around
 
1531
            before_wrap = self._read_slice(tail, self.max_size)
 
1532
            after_wrap = self._read_slice(0, head)
 
1533
            return before_wrap + after_wrap
 
1534
        else:
 
1535
            # Just from here to head
 
1536
            return self._read_slice(tail, head)
 
1537
 
 
1538
    def write(self, data):
 
1539
        """Write some amount of data to the ringbuffer, discarding the oldest
 
1540
        data as max_size is exceeded."""
 
1541
        head, tail = self._read_header()
 
1542
        while data:
 
1543
            # Amount of data to be written on this pass
 
1544
            len_to_write = min(len(data), self.max_size - head)
 
1545
 
 
1546
            # Where head will be after this write
 
1547
            new_head = head + len_to_write
 
1548
 
 
1549
            # In the next comparison, new_head may be self.max_size which is
 
1550
            # logically the same point as tail == 0 and must still be within
 
1551
            # the range tested.
 
1552
            unwrapped_tail = tail if tail else self.max_size
 
1553
 
 
1554
            if head < unwrapped_tail <= new_head:
 
1555
                # Write will go past tail so tail needs to be pushed back
 
1556
                tail = new_head + 1  # one past head to indicate full
 
1557
                tail %= self.max_size
 
1558
                self._write_header(head, tail)
 
1559
 
 
1560
            # Write the data
 
1561
            self._write_slice(head, data[:len_to_write])
 
1562
            data = data[len_to_write:]  # data now left
 
1563
 
 
1564
            # Push head back
 
1565
            head = new_head
 
1566
            head %= self.max_size
 
1567
            self._write_header(head, tail)
 
1568
 
 
1569
    def flush(self):
 
1570
        self.f.flush()
 
1571
 
 
1572
    def close(self):
 
1573
        self.f.close()