rather comprehensive style fixes

This commit is contained in:
andy
2010-08-16 14:16:21 +02:00
parent c395dd793d
commit d508418214
39 changed files with 208 additions and 145 deletions

View File

@@ -20,6 +20,7 @@ Nova User API client library.
"""
import base64
import boto
from boto.ec2.regioninfo import RegionInfo
@@ -57,6 +58,7 @@ class UserInfo(object):
elif name == 'secretkey':
self.secretkey = str(value)
class UserRole(object):
"""
Information about a Nova user's role, as parsed through SAX.
@@ -79,6 +81,7 @@ class UserRole(object):
else:
setattr(self, name, str(value))
class ProjectInfo(object):
"""
Information about a Nova project, as parsed through SAX
@@ -114,12 +117,14 @@ class ProjectInfo(object):
else:
setattr(self, name, str(value))
class ProjectMember(object):
"""
Information about a Nova project member, as parsed through SAX.
Fields include:
memberId
"""
def __init__(self, connection=None):
self.connection = connection
self.memberId = None
@@ -135,6 +140,7 @@ class ProjectMember(object):
self.memberId = value
else:
setattr(self, name, str(value))
class HostInfo(object):
"""
@@ -163,6 +169,7 @@ class HostInfo(object):
def endElement(self, name, value, connection):
setattr(self, name, value)
class NovaAdminClient(object):
def __init__(self, clc_ip='127.0.0.1', region='nova', access_key='admin',
secret_key='admin', **kwargs):

View File

@@ -219,7 +219,6 @@ class FakeLDAP(object):
raise NO_SUCH_OBJECT()
return objects
@property
def __redis_prefix(self):
return 'ldap:'

View File

@@ -30,6 +30,7 @@ import sys
from nova import exception
from nova import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('ldap_url', 'ldap://localhost',
'Point this at your ldap server')

View File

@@ -37,7 +37,6 @@ from nova.network import vpn
FLAGS = flags.FLAGS
flags.DEFINE_list('allowed_roles',
['cloudadmin', 'itsec', 'sysadmin', 'netadmin', 'developer'],
'Allowed roles for project')
@@ -52,7 +51,6 @@ flags.DEFINE_list('superuser_roles', ['cloudadmin'],
flags.DEFINE_list('global_roles', ['cloudadmin', 'itsec'],
'Roles that apply to all projects')
flags.DEFINE_string('credentials_template',
utils.abspath('auth/novarc.template'),
'Template for creating users rc file')
@@ -67,15 +65,14 @@ flags.DEFINE_string('credential_cert_file', 'cert.pem',
'Filename of certificate in credentials zip')
flags.DEFINE_string('credential_rc_file', 'novarc',
'Filename of rc in credentials zip')
flags.DEFINE_string('credential_cert_subject',
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
'OU=NovaDev/CN=%s-%s',
'Subject for certificate for users')
flags.DEFINE_string('auth_driver', 'nova.auth.ldapdriver.FakeLdapDriver',
'Driver that auth manager uses')
class AuthBase(object):
"""Base class for objects relating to auth
@@ -83,6 +80,7 @@ class AuthBase(object):
an id member. They may optionally contain methods that delegate to
AuthManager, but should not implement logic themselves.
"""
@classmethod
def safe_id(cls, obj):
"""Safe get object id
@@ -100,6 +98,7 @@ class AuthBase(object):
class User(AuthBase):
"""Object representing a user"""
def __init__(self, id, name, access, secret, admin):
AuthBase.__init__(self)
self.id = id
@@ -161,6 +160,7 @@ class KeyPair(AuthBase):
Even though this object is named KeyPair, only the public key and
fingerprint is stored. The user's private key is not saved.
"""
def __init__(self, id, name, owner_id, public_key, fingerprint):
AuthBase.__init__(self)
self.id = id
@@ -179,6 +179,7 @@ class KeyPair(AuthBase):
class Project(AuthBase):
"""Represents a Project returned from the datastore"""
def __init__(self, id, name, project_manager_id, description, member_ids):
AuthBase.__init__(self)
self.id = id
@@ -227,7 +228,6 @@ class Project(AuthBase):
self.member_ids)
class AuthManager(object):
"""Manager Singleton for dealing with Users, Projects, and Keypairs
@@ -239,7 +239,9 @@ class AuthManager(object):
AuthManager also manages associated data related to Auth objects that
need to be more accessible, such as vpn ips and ports.
"""
_instance = None
def __new__(cls, *args, **kwargs):
"""Returns the AuthManager singleton"""
if not cls._instance:

View File

@@ -32,6 +32,7 @@ def allow(*roles):
return wrapped_f
return wrap
def deny(*roles):
def wrap(f):
def wrapped_f(self, context, *args, **kwargs):
@@ -44,6 +45,7 @@ def deny(*roles):
return wrapped_f
return wrap
def __matches_role(context, role):
if role == 'all':
return True

View File

@@ -48,11 +48,15 @@ import hashlib
import hmac
import logging
import urllib
import boto # NOTE(vish): for new boto
import boto.utils # NOTE(vish): for old boto
# NOTE(vish): for new boto
import boto
# NOTE(vish): for old boto
import boto.utils
from nova.exception import Error
class Signer(object):
""" hacked up code from boto/connection.py """
@@ -77,7 +81,6 @@ class Signer(object):
return self._calc_signature_2(params, verb, server_string, path)
raise Error('Unknown Signature Version: %s' % self.SignatureVersion)
def _get_utf8_value(self, value):
if not isinstance(value, str) and not isinstance(value, unicode):
value = str(value)
@@ -133,5 +136,6 @@ class Signer(object):
logging.debug('base64 encoded digest: %s' % b64)
return b64
if __name__ == '__main__':
print Signer('foo').generate({"SignatureMethod": 'HmacSHA256', 'SignatureVersion': '2'}, "get", "server", "/foo")

View File

@@ -21,9 +21,10 @@ Tornado REST API Request Handlers for CloudPipe
"""
import logging
import tornado.web
import urllib
import tornado.web
from nova import crypto
from nova.auth import manager

View File

@@ -36,11 +36,11 @@ from nova.endpoint import api
FLAGS = flags.FLAGS
flags.DEFINE_string('boot_script_template',
utils.abspath('cloudpipe/bootscript.sh'),
'Template for script to run on cloudpipe instance boot')
class CloudPipe(object):
def __init__(self, cloud_controller):
self.controller = cloud_controller

View File

@@ -24,6 +24,7 @@ Includes injection of SSH PGP keys into authorized_keys file.
import logging
import os
import tempfile
from twisted.internet import defer
from nova import exception
@@ -84,6 +85,7 @@ def partition(infile, outfile, local_bytes=0, local_type='ext2', execute=None):
yield execute('dd if=%s of=%s bs=%d seek=%d conv=notrunc,fsync'
% (infile, outfile, sector_size, primary_first))
@defer.inlineCallbacks
def inject_data(image, key=None, net=None, partition=None, execute=None):
"""Injects a ssh key and optionally net data into a disk image.
@@ -137,6 +139,7 @@ def inject_data(image, key=None, net=None, partition=None, execute=None):
# remove loopback
yield execute('sudo losetup -d %s' % device)
@defer.inlineCallbacks
def _inject_key_into_fs(key, fs, execute=None):
sshdir = os.path.join(os.path.join(fs, 'root'), '.ssh')
@@ -146,6 +149,7 @@ def _inject_key_into_fs(key, fs, execute=None):
keyfile = os.path.join(sshdir, 'authorized_keys')
yield execute('sudo tee -a %s' % keyfile, '\n' + key.strip() + '\n')
@defer.inlineCallbacks
def _inject_net_into_fs(net, fs, execute=None):
netfile = os.path.join(os.path.join(os.path.join(

View File

@@ -168,6 +168,7 @@ class Instance(datastore.BasicModel):
self.unassociate_with("ip", self.state['private_dns_name'])
return super(Instance, self).destroy()
class Host(datastore.BasicModel):
"""A Host is the machine where a Daemon is running."""
@@ -235,6 +236,7 @@ class Daemon(datastore.BasicModel):
for x in cls.associated_to("host", hostname):
yield x
class SessionToken(datastore.BasicModel):
"""This is a short-lived auth token that is passed through web requests"""

View File

@@ -24,14 +24,15 @@ Instance Monitoring:
in the object store.
"""
import boto
import boto.s3
import datetime
import logging
import os
import rrdtool
import sys
import time
import boto
import boto.s3
import rrdtool
from twisted.internet import defer
from twisted.internet import task
from twisted.application import service
@@ -41,13 +42,12 @@ from nova.virt import connection as virt_connection
FLAGS = flags.FLAGS
flags.DEFINE_integer(
'monitoring_instances_delay', 5, 'Sleep time between updates')
flags.DEFINE_integer(
'monitoring_instances_step', 300, 'Interval of RRD updates')
flags.DEFINE_string(
'monitoring_rrd_path', '/var/nova/monitor/instances',
'Location of RRD files')
flags.DEFINE_integer('monitoring_instances_delay', 5,
'Sleep time between updates')
flags.DEFINE_integer('monitoring_instances_step', 300,
'Interval of RRD updates')
flags.DEFINE_string('monitoring_rrd_path', '/var/nova/monitor/instances',
'Location of RRD files')
RRD_VALUES = {
@@ -61,7 +61,7 @@ RRD_VALUES = {
'RRA:MAX:0.5:6:800',
'RRA:MAX:0.5:24:800',
'RRA:MAX:0.5:288:800',
],
],
'net': [
'DS:rx:COUNTER:600:0:1250000',
'DS:tx:COUNTER:600:0:1250000',
@@ -73,7 +73,7 @@ RRD_VALUES = {
'RRA:MAX:0.5:6:800',
'RRA:MAX:0.5:24:800',
'RRA:MAX:0.5:288:800',
],
],
'disk': [
'DS:rd:COUNTER:600:U:U',
'DS:wr:COUNTER:600:U:U',
@@ -85,12 +85,13 @@ RRD_VALUES = {
'RRA:MAX:0.5:6:800',
'RRA:MAX:0.5:24:800',
'RRA:MAX:0.5:444:800',
]
}
]
}
utcnow = datetime.datetime.utcnow
def update_rrd(instance, name, data):
"""
Updates the specified RRD file.
@@ -106,6 +107,7 @@ def update_rrd(instance, name, data):
'%d:%s' % (timestamp, data)
)
def init_rrd(instance, name):
"""
Initializes the specified RRD file.
@@ -124,6 +126,7 @@ def init_rrd(instance, name):
'--start', '0',
*RRD_VALUES[name]
)
def graph_cpu(instance, duration):
"""
@@ -148,6 +151,7 @@ def graph_cpu(instance, duration):
store_graph(instance.instance_id, filename)
def graph_net(instance, duration):
"""
Creates a graph of network usage for the specified instance and duration.
@@ -174,6 +178,7 @@ def graph_net(instance, duration):
)
store_graph(instance.instance_id, filename)
def graph_disk(instance, duration):
"""
@@ -202,6 +207,7 @@ def graph_disk(instance, duration):
store_graph(instance.instance_id, filename)
def store_graph(instance_id, filename):
"""
Transmits the specified graph file to internal object store on cloud
@@ -387,6 +393,7 @@ class InstanceMonitor(object, service.Service):
"""
Monitors the running instances of the current machine.
"""
def __init__(self):
"""
Initialize the monitoring loop.

View File

@@ -29,6 +29,7 @@ import json
import logging
import os
import sys
from twisted.internet import defer
from twisted.internet import task

View File

@@ -24,7 +24,6 @@ SSH keypairs and x509 certificates.
import base64
import hashlib
import logging
import M2Crypto
import os
import shutil
import struct
@@ -32,6 +31,8 @@ import tempfile
import time
import utils
import M2Crypto
from nova import exception
from nova import flags
@@ -42,11 +43,13 @@ flags.DEFINE_string('keys_path', utils.abspath('../keys'), 'Where we keep our ke
flags.DEFINE_string('ca_path', utils.abspath('../CA'), 'Where we keep our root CA')
flags.DEFINE_boolean('use_intermediate_ca', False, 'Should we use intermediate CAs for each project?')
def ca_path(project_id):
if project_id:
return "%s/INTER/%s/cacert.pem" % (FLAGS.ca_path, project_id)
return "%s/cacert.pem" % (FLAGS.ca_path)
def fetch_ca(project_id=None, chain=True):
if not FLAGS.use_intermediate_ca:
project_id = None
@@ -60,6 +63,7 @@ def fetch_ca(project_id=None, chain=True):
buffer += cafile.read()
return buffer
def generate_key_pair(bits=1024):
# what is the magic 65537?
@@ -109,6 +113,7 @@ def generate_x509_cert(subject, bits=1024):
shutil.rmtree(tmpdir)
return (private_key, csr)
def sign_csr(csr_text, intermediate=None):
if not FLAGS.use_intermediate_ca:
intermediate = None
@@ -122,6 +127,7 @@ def sign_csr(csr_text, intermediate=None):
os.chdir(start)
return _sign_csr(csr_text, user_ca)
def _sign_csr(csr_text, ca_folder):
tmpfolder = tempfile.mkdtemp()
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")

View File

@@ -37,6 +37,7 @@ def user_dict(user, base64_file=None):
else:
return {}
def project_dict(project):
"""Convert the project object to a result dict"""
if project:
@@ -47,6 +48,7 @@ def project_dict(project):
else:
return {}
def host_dict(host):
"""Convert a host model object to a result dict"""
if host:
@@ -54,6 +56,7 @@ def host_dict(host):
else:
return {}
def admin_only(target):
"""Decorator for admin-only API calls"""
def wrapper(*args, **kwargs):
@@ -66,6 +69,7 @@ def admin_only(target):
return wrapper
class AdminController(object):
"""
API Controller for users, hosts, nodes, and workers.

View File

@@ -25,12 +25,13 @@ import logging
import multiprocessing
import random
import re
import tornado.web
from twisted.internet import defer
import urllib
# TODO(termie): replace minidom with etree
from xml.dom import minidom
import tornado.web
from twisted.internet import defer
from nova import crypto
from nova import exception
from nova import flags
@@ -43,6 +44,7 @@ from nova.endpoint import cloud
FLAGS = flags.FLAGS
flags.DEFINE_integer('cc_port', 8773, 'cloud controller port')
_log = logging.getLogger("api")
_log.setLevel(logging.DEBUG)
@@ -227,6 +229,7 @@ class MetadataRequestHandler(tornado.web.RequestHandler):
self.print_data(data)
self.finish()
class APIRequestHandler(tornado.web.RequestHandler):
def get(self, controller_name):
self.execute(controller_name)

View File

@@ -26,6 +26,7 @@ import base64
import logging
import os
import time
from twisted.internet import defer
from nova import datastore
@@ -44,7 +45,6 @@ from nova.volume import service
FLAGS = flags.FLAGS
flags.DEFINE_string('cloud_topic', 'cloud', 'the topic clouds listen on')
@@ -362,7 +362,6 @@ class CloudController(object):
'status': volume['attach_status'],
'volumeId': volume_id})
@rbac.allow('projectmanager', 'sysadmin')
def detach_volume(self, context, volume_id, **kwargs):
volume = self._get_volume(context, volume_id)

View File

@@ -21,10 +21,11 @@ Proxy AMI-related calls from the cloud controller, to the running
objectstore daemon.
"""
import boto.s3.connection
import json
import urllib
import boto.s3.connection
from nova import flags
from nova import utils
from nova.auth import manager
@@ -32,6 +33,7 @@ from nova.auth import manager
FLAGS = flags.FLAGS
def modify(context, image_id, operation):
conn(context).make_request(
method='POST',
@@ -53,6 +55,7 @@ def register(context, image_location):
return image_id
def list(context, filter_list=[]):
""" return a list of all images that a user can see
@@ -68,6 +71,7 @@ def list(context, filter_list=[]):
return [i for i in result if i['imageId'] in filter_list]
return result
def deregister(context, image_id):
""" unregister an image """
conn(context).make_request(
@@ -75,6 +79,7 @@ def deregister(context, image_id):
bucket='_images',
query_args=qs({'image_id': image_id}))
def conn(context):
access = manager.AuthManager().get_access_key(context.user,
context.project)

View File

@@ -25,31 +25,39 @@ import logging
import sys
import traceback
class Error(Exception):
def __init__(self, message=None):
super(Error, self).__init__(message)
class ApiError(Error):
def __init__(self, message='Unknown', code='Unknown'):
self.message = message
self.code = code
super(ApiError, self).__init__('%s: %s'% (code, message))
class NotFound(Error):
pass
class Duplicate(Error):
pass
class NotAuthorized(Error):
pass
class NotEmpty(Error):
pass
class Invalid(Error):
pass
def wrap_exception(f):
def _wrap(*args, **kw):
try:

View File

@@ -16,12 +16,13 @@
# License for the specific language governing permissions and limitations
# under the License.
""" Based a bit on the carrot.backeds.queue backend... but a lot better """
"""Based a bit on the carrot.backeds.queue backend... but a lot better."""
from carrot.backends import base
import logging
import Queue as queue
from carrot.backends import base
class Message(base.BaseMessage):
pass

View File

@@ -175,29 +175,25 @@ DEFINE_string('network_topic', 'network', 'the topic network nodes listen on')
DEFINE_bool('verbose', False, 'show debug output')
DEFINE_boolean('fake_rabbit', False, 'use a fake rabbit')
DEFINE_bool('fake_network', False, 'should we use fake network devices and addresses')
DEFINE_bool('fake_network', False,
'should we use fake network devices and addresses')
DEFINE_string('rabbit_host', 'localhost', 'rabbit host')
DEFINE_integer('rabbit_port', 5672, 'rabbit port')
DEFINE_string('rabbit_userid', 'guest', 'rabbit userid')
DEFINE_string('rabbit_password', 'guest', 'rabbit password')
DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
DEFINE_string('ec2_url',
'http://127.0.0.1:8773/services/Cloud',
'Url to ec2 api server')
DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
'Url to ec2 api server')
DEFINE_string('default_image',
'ami-11111',
'default image to use, testing only')
DEFINE_string('default_kernel',
'aki-11111',
'default kernel to use, testing only')
DEFINE_string('default_ramdisk',
'ari-11111',
'default ramdisk to use, testing only')
DEFINE_string('default_instance_type',
'm1.small',
'default instance type to use, testing only')
DEFINE_string('default_image', 'ami-11111',
'default image to use, testing only')
DEFINE_string('default_kernel', 'aki-11111',
'default kernel to use, testing only')
DEFINE_string('default_ramdisk', 'ari-11111',
'default ramdisk to use, testing only')
DEFINE_string('default_instance_type', 'm1.small',
'default instance type to use, testing only')
DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server')
DEFINE_string('vpn_key_suffix',
@@ -207,10 +203,8 @@ DEFINE_string('vpn_key_suffix',
DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
# UNUSED
DEFINE_string('node_availability_zone',
'nova',
'availability zone of this node')
DEFINE_string('node_name',
socket.gethostname(),
'name of this node')
DEFINE_string('node_availability_zone', 'nova',
'availability zone of this node')
DEFINE_string('node_name', socket.gethostname(),
'name of this node')

View File

@@ -20,29 +20,29 @@
Exceptions for network errors.
"""
from nova.exception import Error
from nova import exception
class NoMoreAddresses(Error):
class NoMoreAddresses(exception.Error):
"""No More Addresses are available in the network"""
pass
class AddressNotAllocated(Error):
class AddressNotAllocated(exception.Error):
"""The specified address has not been allocated"""
pass
class AddressAlreadyAssociated(Error):
class AddressAlreadyAssociated(exception.Error):
"""The specified address has already been associated"""
pass
class AddressNotAssociated(Error):
class AddressNotAssociated(exception.Error):
"""The specified address is not associated"""
pass
class NotValidNetworkSize(Error):
class NotValidNetworkSize(exception.Error):
"""The network size is not valid"""
pass

View File

@@ -18,16 +18,16 @@ Implements vlans, bridges, and iptables rules using linux utilities.
"""
import logging
import signal
import os
import signal
# todo(ja): does the definition of network_path belong here?
# TODO(ja): does the definition of network_path belong here?
from nova import flags
from nova import utils
FLAGS = flags.FLAGS
FLAGS = flags.FLAGS
flags.DEFINE_string('dhcpbridge_flagfile',
'/etc/nova/nova-dhcpbridge.conf',
'location of flagfile for dhcpbridge')

View File

@@ -20,11 +20,11 @@
Model Classes for network control, including VLANs, DHCP, and IP allocation.
"""
import IPy
import logging
import os
import time
import IPy
from nova import datastore
from nova import exception as nova_exception
from nova import flags
@@ -53,6 +53,7 @@ flags.DEFINE_integer('cnt_vpn_clients', 5,
flags.DEFINE_integer('cloudpipe_start_port', 12000,
'Starting port for mapped CloudPipe external ports')
logging.getLogger().setLevel(logging.DEBUG)

View File

@@ -21,17 +21,17 @@ Network Hosts are responsible for allocating ips and setting up network
"""
from nova import datastore
from nova import exception
from nova import flags
from nova import service
from nova import utils
from nova.auth import manager
from nova.exception import NotFound
from nova.network import exception
from nova.network import model
from nova.network import vpn
FLAGS = flags.FLAGS
FLAGS = flags.FLAGS
flags.DEFINE_string('network_type',
'flat',
'Service Class for Networking')
@@ -41,15 +41,15 @@ flags.DEFINE_list('flat_network_ips',
['192.168.0.2', '192.168.0.3', '192.168.0.4'],
'Available ips for simple network')
flags.DEFINE_string('flat_network_network', '192.168.0.0',
'Network for simple network')
'Network for simple network')
flags.DEFINE_string('flat_network_netmask', '255.255.255.0',
'Netmask for simple network')
'Netmask for simple network')
flags.DEFINE_string('flat_network_gateway', '192.168.0.1',
'Broadcast for simple network')
'Broadcast for simple network')
flags.DEFINE_string('flat_network_broadcast', '192.168.0.255',
'Broadcast for simple network')
'Broadcast for simple network')
flags.DEFINE_string('flat_network_dns', '8.8.4.4',
'Dns for simple network')
'Dns for simple network')
def type_to_class(network_type):
@@ -58,7 +58,7 @@ def type_to_class(network_type):
return FlatNetworkService
elif network_type == 'vlan':
return VlanNetworkService
raise NotFound("Couldn't find %s network type" % network_type)
raise exception.NotFound("Couldn't find %s network type" % network_type)
def setup_compute_network(network_type, user_id, project_id, security_group):

View File

@@ -23,9 +23,8 @@ from nova import exception
from nova import flags
from nova import utils
FLAGS = flags.FLAGS
flags.DEFINE_string('vpn_ip', utils.get_my_ip(),
'Public IP for the cloudpipe VPN servers')
flags.DEFINE_integer('vpn_start_port', 1000,

View File

@@ -36,6 +36,7 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('buckets_path', utils.abspath('../buckets'),
'path to s3 buckets')
class Bucket(object):
def __init__(self, name):
self.name = name

View File

@@ -38,17 +38,19 @@ S3 client with this module::
"""
import datetime
import logging
import json
import logging
import multiprocessing
import os
from tornado import escape
import urllib
from twisted.application import internet, service
from twisted.web.resource import Resource
from twisted.web import server, static, error
from tornado import escape
from twisted.application import internet
from twisted.application import service
from twisted.web import error
from twisted.web import resource
from twisted.web import server
from twisted.web import static
from nova import exception
from nova import flags
@@ -60,6 +62,7 @@ from nova.objectstore import image
FLAGS = flags.FLAGS
def render_xml(request, value):
assert isinstance(value, dict) and len(value) == 1
request.setHeader("Content-Type", "application/xml; charset=UTF-8")
@@ -72,11 +75,13 @@ def render_xml(request, value):
request.write('</' + escape.utf8(name) + '>')
request.finish()
def finish(request, content=None):
if content:
request.write(content)
request.finish()
def _render_parts(value, write_cb):
if isinstance(value, basestring):
write_cb(escape.xhtml_escape(value))
@@ -95,11 +100,13 @@ def _render_parts(value, write_cb):
else:
raise Exception("Unknown S3 value type %r", value)
def get_argument(request, key, default_value):
if key in request.args:
return request.args[key][0]
return default_value
def get_context(request):
try:
# Authorization Header format: 'AWS <access>:<secret>'
@@ -120,13 +127,14 @@ def get_context(request):
logging.debug("Authentication Failure: %s" % ex)
raise exception.NotAuthorized
class ErrorHandlingResource(Resource):
class ErrorHandlingResource(resource.Resource):
"""Maps exceptions to 404 / 401 codes. Won't work for exceptions thrown after NOT_DONE_YET is returned."""
# TODO(unassigned) (calling-all-twisted-experts): This needs to be plugged in to the right place in twisted...
# This doesn't look like it's the right place (consider exceptions in getChild; or after NOT_DONE_YET is returned
def render(self, request):
try:
return Resource.render(self, request)
return resource.Resource.render(self, request)
except exception.NotFound:
request.setResponseCode(404)
return ''
@@ -134,6 +142,7 @@ class ErrorHandlingResource(Resource):
request.setResponseCode(403)
return ''
class S3(ErrorHandlingResource):
"""Implementation of an S3-like storage server based on local files."""
def getChild(self, name, request):
@@ -154,9 +163,10 @@ class S3(ErrorHandlingResource):
}})
return server.NOT_DONE_YET
class BucketResource(ErrorHandlingResource):
def __init__(self, name):
Resource.__init__(self)
resource.Resource.__init__(self)
self.name = name
def getChild(self, name, request):
@@ -206,7 +216,7 @@ class BucketResource(ErrorHandlingResource):
class ObjectResource(ErrorHandlingResource):
def __init__(self, bucket, name):
Resource.__init__(self)
resource.Resource.__init__(self)
self.bucket = bucket
self.name = name
@@ -245,17 +255,19 @@ class ObjectResource(ErrorHandlingResource):
request.setResponseCode(204)
return ''
class ImageResource(ErrorHandlingResource):
isLeaf = True
def __init__(self, name):
Resource.__init__(self)
resource.Resource.__init__(self)
self.img = image.Image(name)
def render_GET(self, request):
return static.File(self.img.image_path, defaultType='application/octet-stream').render_GET(request)
class ImagesResource(Resource):
class ImagesResource(resource.Resource):
def getChild(self, name, request):
if name == '':
return self
@@ -339,11 +351,13 @@ class ImagesResource(Resource):
request.setResponseCode(204)
return ''
def get_site():
root = S3()
site = server.Site(root)
return site
def get_application():
factory = get_site()
application = service.Application("objectstore")

View File

@@ -42,6 +42,7 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('images_path', utils.abspath('../images'),
'path to decrypted images')
class Image(object):
def __init__(self, image_id):
self.image_id = image_id

View File

@@ -23,7 +23,7 @@ Properties of an object stored within a bucket.
import os
import nova.crypto
from nova.exception import NotFound, NotAuthorized
from nova import exception
class Object(object):
@@ -33,7 +33,7 @@ class Object(object):
self.key = key
self.path = bucket._object_path(key)
if not os.path.isfile(self.path):
raise NotFound
raise exception.NotFound
def __repr__(self):
return "<Object %s/%s>" % (self.bucket, self.key)

View File

@@ -23,6 +23,7 @@ Process pool, still buggy right now.
import logging
import multiprocessing
import StringIO
from twisted.internet import defer
from twisted.internet import error
from twisted.internet import process
@@ -205,6 +206,7 @@ class ProcessPool(object):
self._pool.release()
return rv
class SharedPool(object):
_instance = None
def __init__(self):
@@ -213,5 +215,6 @@ class SharedPool(object):
def __getattr__(self, key):
return getattr(self._instance, key)
def simple_execute(cmd, **kwargs):
return SharedPool().simple_execute(cmd, **kwargs)

View File

@@ -21,12 +21,13 @@ AMQP-based RPC. Queues have consumers and publishers.
No fan-out support yet.
"""
from carrot import connection as carrot_connection
from carrot import messaging
import json
import logging
import sys
import uuid
from carrot import connection as carrot_connection
from carrot import messaging
from twisted.internet import defer
from twisted.internet import task

View File

@@ -22,11 +22,11 @@ Allows overriding of flags for use of fakes,
and some black magic for inline callbacks.
"""
import mox
import stubout
import sys
import time
import mox
import stubout
from tornado import ioloop
from twisted.internet import defer
from twisted.trial import unittest
@@ -91,7 +91,6 @@ class TrialTestCase(unittest.TestCase):
setattr(FLAGS, k, v)
class BaseTestCase(TrialTestCase):
# TODO(jaypipes): Can this be moved into the TrialTestCase class?
"""Base test case class for all unit tests."""

View File

@@ -20,7 +20,7 @@
System-level utilities and helper functions.
"""
from datetime import datetime, timedelta
import datetime
import inspect
import logging
import os
@@ -32,9 +32,11 @@ import sys
from nova import exception
from nova import flags
FLAGS = flags.FLAGS
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
def import_class(import_str):
"""Returns a class from a string including module and class"""
mod_str, _sep, class_str = import_str.rpartition('.')
@@ -44,6 +46,7 @@ def import_class(import_str):
except (ImportError, ValueError, AttributeError):
raise exception.NotFound('Class %s cannot be found' % class_str)
def fetchfile(url, target):
logging.debug("Fetching %s" % url)
# c = pycurl.Curl()
@@ -55,6 +58,7 @@ def fetchfile(url, target):
# fp.close()
execute("curl %s -o %s" % (url, target))
def execute(cmd, input=None, addl_env=None):
env = os.environ.copy()
if addl_env:
@@ -129,10 +133,12 @@ def get_my_ip():
logging.warn("Couldn't get IP, using 127.0.0.1 %s", ex)
return "127.0.0.1"
def isotime(at=None):
if not at:
at = datetime.utcnow()
at = datetime.datetime.utcnow()
return at.strftime(TIME_FORMAT)
def parse_isotime(timestr):
return datetime.strptime(timestr, TIME_FORMAT)
return datetime.datetime.strptime(timestr, TIME_FORMAT)

View File

@@ -57,6 +57,7 @@ def rangetest(**argchecks): # validate ranges for both+defaults
return onCall
return onDecorator
def typetest(**argchecks):
def onDecorator(func):
import sys

View File

@@ -27,11 +27,11 @@ import urlparse
from nova import flags
from nova import process
from nova.auth import signer
from nova.auth import manager
from nova.auth import signer
FLAGS = flags.FLAGS
flags.DEFINE_bool('use_s3', True,
'whether to get images from s3 or use local copy')
@@ -43,6 +43,7 @@ def fetch(image, path, user, project):
f = _fetch_local_image
return f(image, path, user, project)
def _fetch_s3_image(image, path, user, project):
url = image_url(image)
@@ -66,13 +67,16 @@ def _fetch_s3_image(image, path, user, project):
cmd += ['-o', path]
return process.SharedPool().execute(executable=cmd[0], args=cmd[1:])
def _fetch_local_image(image, path, user, project):
source = _image_path('%s/image' % image)
return process.simple_execute('cp %s %s' % (source, path))
def _image_path(path):
return os.path.join(FLAGS.images_path, path)
def image_url(image):
return "http://%s:%s/_images/%s/image" % (FLAGS.s3_host, FLAGS.s3_port,
image)

View File

@@ -42,6 +42,7 @@ from nova.virt import images
libvirt = None
libxml2 = None
FLAGS = flags.FLAGS
flags.DEFINE_string('libvirt_xml_template',
utils.abspath('virt/libvirt.qemu.xml.template'),
@@ -57,7 +58,9 @@ flags.DEFINE_string('libvirt_type',
'Libvirt domain type (valid options are: kvm, qemu, uml)')
flags.DEFINE_string('libvirt_uri',
'',
'Override the default libvirt URI (which is dependent on libvirt_type)')
'Override the default libvirt URI (which is dependent'
' on libvirt_type)')
def get_connection(read_only):
# These are loaded late so that there's no need to install these
@@ -70,6 +73,7 @@ def get_connection(read_only):
libxml2 = __import__('libxml2')
return LibvirtConnection(read_only)
class LibvirtConnection(object):
def __init__(self, read_only):
self.libvirt_uri, template_file = self.get_uri_and_template()
@@ -78,14 +82,12 @@ class LibvirtConnection(object):
self._wrapped_conn = None
self.read_only = read_only
@property
def _conn(self):
if not self._wrapped_conn:
self._wrapped_conn = self._connect(self.libvirt_uri, self.read_only)
return self._wrapped_conn
def get_uri_and_template(self):
if FLAGS.libvirt_type == 'uml':
uri = FLAGS.libvirt_uri or 'uml:///system'
@@ -95,7 +97,6 @@ class LibvirtConnection(object):
template_file = FLAGS.libvirt_xml_template
return uri, template_file
def _connect(self, uri, read_only):
auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],
'root',
@@ -106,13 +107,10 @@ class LibvirtConnection(object):
else:
return libvirt.openAuth(uri, auth, 0)
def list_instances(self):
return [self._conn.lookupByID(x).name()
for x in self._conn.listDomainsID()]
def destroy(self, instance):
try:
virt_dom = self._conn.lookupByName(instance.name)
@@ -141,14 +139,12 @@ class LibvirtConnection(object):
timer.start(interval=0.5, now=True)
return d
def _cleanup(self, instance):
target = os.path.abspath(instance.datamodel['basepath'])
logging.info("Deleting instance files at %s", target)
if os.path.exists(target):
shutil.rmtree(target)
@defer.inlineCallbacks
@exception.wrap_exception
def reboot(self, instance):
@@ -174,7 +170,6 @@ class LibvirtConnection(object):
timer.start(interval=0.5, now=True)
yield d
@defer.inlineCallbacks
@exception.wrap_exception
def spawn(self, instance):
@@ -205,7 +200,6 @@ class LibvirtConnection(object):
timer.start(interval=0.5, now=True)
yield local_d
@defer.inlineCallbacks
def _create_image(self, instance, libvirt_xml):
# syntactic nicety
@@ -260,11 +254,9 @@ class LibvirtConnection(object):
yield disk.partition(
basepath('disk-raw'), basepath('disk'), bytes, execute=execute)
def basepath(self, instance, path=''):
return os.path.abspath(os.path.join(instance.datamodel['basepath'], path))
def toXml(self, instance):
# TODO(termie): cache?
logging.debug("Starting the toXML method")
@@ -279,7 +271,6 @@ class LibvirtConnection(object):
return libvirt_xml
def get_info(self, instance_id):
virt_dom = self._conn.lookupByName(instance_id)
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
@@ -289,7 +280,6 @@ class LibvirtConnection(object):
'num_cpu': num_cpu,
'cpu_time': cpu_time}
def get_disks(self, instance_id):
"""
Note that this function takes an instance ID, not an Instance, so
@@ -332,7 +322,6 @@ class LibvirtConnection(object):
return disks
def get_interfaces(self, instance_id):
"""
Note that this function takes an instance ID, not an Instance, so
@@ -375,7 +364,6 @@ class LibvirtConnection(object):
return interfaces
def block_stats(self, instance_id, disk):
"""
Note that this function takes an instance ID, not an Instance, so
@@ -384,7 +372,6 @@ class LibvirtConnection(object):
domain = self._conn.lookupByName(instance_id)
return domain.blockStats(disk)
def interface_stats(self, instance_id, interface):
"""
Note that this function takes an instance ID, not an Instance, so

View File

@@ -33,16 +33,29 @@ from nova.virt import images
XenAPI = None
FLAGS = flags.FLAGS
flags.DEFINE_string('xenapi_connection_url',
None,
'URL for connection to XenServer/Xen Cloud Platform. Required if connection_type=xenapi.')
'URL for connection to XenServer/Xen Cloud Platform.'
' Required if connection_type=xenapi.')
flags.DEFINE_string('xenapi_connection_username',
'root',
'Username for connection to XenServer/Xen Cloud Platform. Used only if connection_type=xenapi.')
'Username for connection to XenServer/Xen Cloud Platform.'
' Used only if connection_type=xenapi.')
flags.DEFINE_string('xenapi_connection_password',
None,
'Password for connection to XenServer/Xen Cloud Platform. Used only if connection_type=xenapi.')
'Password for connection to XenServer/Xen Cloud Platform.'
' Used only if connection_type=xenapi.')
XENAPI_POWER_STATE = {
'Halted' : power_state.SHUTDOWN,
'Running' : power_state.RUNNING,
'Paused' : power_state.PAUSED,
'Suspended': power_state.SHUTDOWN, # FIXME
'Crashed' : power_state.CRASHED
}
def get_connection(_):
@@ -62,7 +75,6 @@ def get_connection(_):
class XenAPIConnection(object):
def __init__(self, url, user, pw):
self._conn = XenAPI.Session(url)
self._conn.login_with_password(user, pw)
@@ -107,7 +119,6 @@ class XenAPIConnection(object):
yield self._create_vif(vm_ref, network_ref, mac_address)
yield self._conn.xenapi.VM.start(vm_ref, False, False)
def create_vm(self, instance, kernel, ramdisk):
mem = str(long(instance.datamodel['memory_kb']) * 1024)
vcpus = str(instance.datamodel['vcpus'])
@@ -145,7 +156,6 @@ class XenAPIConnection(object):
logging.debug('Created VM %s as %s.', instance.name, vm_ref)
return vm_ref
def create_vbd(self, vm_ref, vdi_ref, userdevice, bootable):
vbd_rec = {}
vbd_rec['VM'] = vm_ref
@@ -166,7 +176,6 @@ class XenAPIConnection(object):
vdi_ref)
return vbd_ref
def _create_vif(self, vm_ref, network_ref, mac_address):
vif_rec = {}
vif_rec['device'] = '0'
@@ -184,7 +193,6 @@ class XenAPIConnection(object):
vm_ref, network_ref)
return vif_ref
def _find_network_with_bridge(self, bridge):
expr = 'field "bridge" = "%s"' % bridge
networks = self._conn.xenapi.network.get_all_records_where(expr)
@@ -195,7 +203,6 @@ class XenAPIConnection(object):
else:
raise Exception('Found no network for bridge %s' % bridge)
def fetch_image(self, image, user, project, use_sr):
"""use_sr: True to put the image as a VDI in an SR, False to place
it on dom0's filesystem. The former is for VM disks, the latter for
@@ -213,7 +220,6 @@ class XenAPIConnection(object):
args['add_partition'] = 'true'
return self._call_plugin('objectstore', fn, args)
def reboot(self, instance):
vm = self.lookup(instance.name)
if vm is None:
@@ -231,7 +237,7 @@ class XenAPIConnection(object):
if vm is None:
raise Exception('instance not present %s' % instance_id)
rec = self._conn.xenapi.VM.get_record(vm)
return {'state': power_state_from_xenapi[rec['power_state']],
return {'state': XENAPI_POWER_STATE[rec['power_state']],
'max_mem': long(rec['memory_static_max']) >> 10,
'mem': long(rec['memory_dynamic_max']) >> 10,
'num_cpu': rec['VCPUs_max'],
@@ -247,26 +253,15 @@ class XenAPIConnection(object):
else:
return vms[0]
def _call_plugin(self, plugin, fn, args):
return _unwrap_plugin_exceptions(
self._conn.xenapi.host.call_plugin,
self._get_xenapi_host(), plugin, fn, args)
def _get_xenapi_host(self):
return self._conn.xenapi.session.get_this_host(self._conn.handle)
power_state_from_xenapi = {
'Halted' : power_state.SHUTDOWN,
'Running' : power_state.RUNNING,
'Paused' : power_state.PAUSED,
'Suspended': power_state.SHUTDOWN, # FIXME
'Crashed' : power_state.CRASHED
}
def _unwrap_plugin_exceptions(func, *args, **kwargs):
try:
return func(*args, **kwargs)

View File

@@ -65,6 +65,7 @@ flags.DEFINE_boolean('fake_storage', False,
class NoMoreBlades(exception.Error):
pass
def get_volume(volume_id):
""" Returns a redis-backed volume object """
volume_class = Volume
@@ -75,6 +76,7 @@ def get_volume(volume_id):
return vol
raise exception.Error("Volume does not exist")
class VolumeService(service.Service):
"""
There is one VolumeNode running on each host.
@@ -142,6 +144,7 @@ class VolumeService(service.Service):
"sudo vgcreate %s %s" % (FLAGS.volume_group,
FLAGS.storage_dev))
class Volume(datastore.BasicModel):
def __init__(self, volume_id=None):
@@ -297,7 +300,6 @@ class Volume(datastore.BasicModel):
self['blade_id']), error_ok=1)
class FakeVolume(Volume):
def _create_lv(self):
pass

View File

@@ -38,11 +38,11 @@ Due to our use of multiprocessing it we frequently get some ignorable
'Interrupted system call' exceptions after test completion.
"""
import __main__
import os
import sys
from twisted.scripts import trial as trial_script
from nova import datastore
@@ -65,13 +65,12 @@ from nova.tests.volume_unittest import *
FLAGS = flags.FLAGS
flags.DEFINE_bool('flush_db', True,
'Flush the database before running fake tests')
flags.DEFINE_string('tests_stderr', 'run_tests.err.log',
'Path to where to pipe STDERR during test runs. '
'Default = "run_tests.err.log"')
'Path to where to pipe STDERR during test runs.'
' Default = "run_tests.err.log"')
if __name__ == '__main__':
OptionsClass = twistd.WrapTwistedOptions(trial_script.Options)