rather comprehensive style fixes
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -219,7 +219,6 @@ class FakeLDAP(object):
|
||||
raise NO_SUCH_OBJECT()
|
||||
return objects
|
||||
|
||||
|
||||
@property
|
||||
def __redis_prefix(self):
|
||||
return 'ldap:'
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"""
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -29,6 +29,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import task
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -57,6 +57,7 @@ def rangetest(**argchecks): # validate ranges for both+defaults
|
||||
return onCall
|
||||
return onDecorator
|
||||
|
||||
|
||||
def typetest(**argchecks):
|
||||
def onDecorator(func):
|
||||
import sys
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user