refactor daemons to use common base class in preparation for network refactor
This commit is contained in:
@@ -19,80 +19,14 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Twistd daemon for the nova compute nodes.
|
Twistd daemon for the nova compute nodes.
|
||||||
Receives messages via AMQP, manages pool of worker threads
|
|
||||||
for async tasks.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# NOTE(termie): kludge so that we can run this from the bin directory in the
|
|
||||||
# checkout without having to screw with paths
|
|
||||||
NOVA_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'nova')
|
|
||||||
if os.path.exists(NOVA_PATH):
|
|
||||||
sys.path.insert(0, os.path.dirname(NOVA_PATH))
|
|
||||||
|
|
||||||
from twisted.internet import task
|
|
||||||
from twisted.application import service
|
|
||||||
|
|
||||||
from nova import flags
|
|
||||||
from nova import rpc
|
|
||||||
from nova import twistd
|
from nova import twistd
|
||||||
from nova.compute import node
|
from nova.compute import node
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
# NOTE(termie): This file will necessarily be re-imported under different
|
|
||||||
# context when the twistd.serve() call is made below so any
|
|
||||||
# flags we define here will have to be conditionally defined,
|
|
||||||
# flags defined by imported modules are safe.
|
|
||||||
if 'compute_report_state_interval' not in FLAGS:
|
|
||||||
flags.DEFINE_integer('compute_report_state_interval', 10,
|
|
||||||
'seconds between nodes reporting state to cloud',
|
|
||||||
lower_bound=1)
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
logging.warn('Starting compute node')
|
|
||||||
n = node.Node()
|
|
||||||
d = n.adopt_instances()
|
|
||||||
d.addCallback(lambda x: logging.info('Adopted %d instances', x))
|
|
||||||
|
|
||||||
conn = rpc.Connection.instance()
|
|
||||||
consumer_all = rpc.AdapterConsumer(
|
|
||||||
connection=conn,
|
|
||||||
topic='%s' % FLAGS.compute_topic,
|
|
||||||
proxy=n)
|
|
||||||
|
|
||||||
consumer_node = rpc.AdapterConsumer(
|
|
||||||
connection=conn,
|
|
||||||
topic='%s.%s' % (FLAGS.compute_topic, FLAGS.node_name),
|
|
||||||
proxy=n)
|
|
||||||
|
|
||||||
bin_name = os.path.basename(__file__)
|
|
||||||
pulse = task.LoopingCall(n.report_state, FLAGS.node_name, bin_name)
|
|
||||||
pulse.start(interval=FLAGS.compute_report_state_interval, now=False)
|
|
||||||
|
|
||||||
consumer_all.attach_to_twisted()
|
|
||||||
consumer_node.attach_to_twisted()
|
|
||||||
|
|
||||||
# This is the parent service that twistd will be looking for when it
|
|
||||||
# parses this file, return it so that we can get it into globals below
|
|
||||||
application = service.Application(bin_name)
|
|
||||||
n.setServiceParent(application)
|
|
||||||
return application
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(termie): When this script is executed from the commandline what it will
|
|
||||||
# actually do is tell the twistd application runner that it
|
|
||||||
# should run this file as a twistd application (see below).
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
twistd.serve(__file__)
|
twistd.serve(__file__)
|
||||||
|
|
||||||
# NOTE(termie): When this script is loaded by the twistd application runner
|
|
||||||
# this code path will be executed and twistd will expect a
|
|
||||||
# variable named 'application' to be available, it will then
|
|
||||||
# handle starting it and stopping it.
|
|
||||||
if __name__ == '__builtin__':
|
if __name__ == '__builtin__':
|
||||||
application = main()
|
application = node.ComputeNode.create()
|
||||||
|
|||||||
32
bin/nova-network
Normal file
32
bin/nova-network
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2010 United States Government as represented by the
|
||||||
|
# Administrator of the National Aeronautics and Space Administration.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Twistd daemon for the nova network nodes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from nova import twistd
|
||||||
|
from nova.network import node
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
twistd.serve(__file__)
|
||||||
|
|
||||||
|
if __name__ == '__builtin__':
|
||||||
|
application = node.NetworkNode.create()
|
||||||
@@ -18,77 +18,15 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Tornado Storage daemon manages AoE volumes via AMQP messaging.
|
Twistd daemon for the nova volume nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# NOTE(termie): kludge so that we can run this from the bin directory in the
|
|
||||||
# checkout without having to screw with paths
|
|
||||||
NOVA_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'nova')
|
|
||||||
if os.path.exists(NOVA_PATH):
|
|
||||||
sys.path.insert(0, os.path.dirname(NOVA_PATH))
|
|
||||||
|
|
||||||
from twisted.internet import task
|
|
||||||
from twisted.application import service
|
|
||||||
|
|
||||||
from nova import flags
|
|
||||||
from nova import rpc
|
|
||||||
from nova import twistd
|
from nova import twistd
|
||||||
from nova.volume import storage
|
from nova.volume import node
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
# NOTE(termie): This file will necessarily be re-imported under different
|
|
||||||
# context when the twistd.serve() call is made below so any
|
|
||||||
# flags we define here will have to be conditionally defined,
|
|
||||||
# flags defined by imported modules are safe.
|
|
||||||
if 'volume_report_state_interval' not in FLAGS:
|
|
||||||
flags.DEFINE_integer('volume_report_state_interval', 10,
|
|
||||||
'seconds between nodes reporting state to cloud',
|
|
||||||
lower_bound=1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
logging.warn('Starting volume node')
|
|
||||||
bs = storage.BlockStore()
|
|
||||||
|
|
||||||
conn = rpc.Connection.instance()
|
|
||||||
consumer_all = rpc.AdapterConsumer(
|
|
||||||
connection=conn,
|
|
||||||
topic='%s' % FLAGS.storage_topic,
|
|
||||||
proxy=bs)
|
|
||||||
|
|
||||||
consumer_node = rpc.AdapterConsumer(
|
|
||||||
connection=conn,
|
|
||||||
topic='%s.%s' % (FLAGS.storage_topic, FLAGS.node_name),
|
|
||||||
proxy=bs)
|
|
||||||
|
|
||||||
bin_name = os.path.basename(__file__)
|
|
||||||
pulse = task.LoopingCall(bs.report_state, FLAGS.node_name, bin_name)
|
|
||||||
pulse.start(interval=FLAGS.volume_report_state_interval, now=False)
|
|
||||||
|
|
||||||
consumer_all.attach_to_twisted()
|
|
||||||
consumer_node.attach_to_twisted()
|
|
||||||
|
|
||||||
# This is the parent service that twistd will be looking for when it
|
|
||||||
# parses this file, return it so that we can get it into globals below
|
|
||||||
application = service.Application(bin_name)
|
|
||||||
bs.setServiceParent(application)
|
|
||||||
return application
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(termie): When this script is executed from the commandline what it will
|
|
||||||
# actually do is tell the twistd application runner that it
|
|
||||||
# should run this file as a twistd application (see below).
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
twistd.serve(__file__)
|
twistd.serve(__file__)
|
||||||
|
|
||||||
# NOTE(termie): When this script is loaded by the twistd application runner
|
|
||||||
# this code path will be executed and twistd will expect a
|
|
||||||
# variable named 'application' to be available, it will then
|
|
||||||
# handle starting it and stopping it.
|
|
||||||
if __name__ == '__builtin__':
|
if __name__ == '__builtin__':
|
||||||
application = main()
|
application = node.VolumeNode.create()
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ from nova.auth import rbac
|
|||||||
from nova.auth import users
|
from nova.auth import users
|
||||||
from nova.compute import model
|
from nova.compute import model
|
||||||
from nova.compute import network
|
from nova.compute import network
|
||||||
from nova.compute import node
|
from nova.compute import computenode
|
||||||
from nova.endpoint import images
|
from nova.endpoint import images
|
||||||
from nova.volume import storage
|
from nova.volume import volumenode
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -76,7 +76,7 @@ class CloudController(object):
|
|||||||
def volumes(self):
|
def volumes(self):
|
||||||
""" returns a list of all volumes """
|
""" returns a list of all volumes """
|
||||||
for volume_id in datastore.Redis.instance().smembers("volumes"):
|
for volume_id in datastore.Redis.instance().smembers("volumes"):
|
||||||
volume = storage.get_volume(volume_id)
|
volume = volumenode.get_volume(volume_id)
|
||||||
yield volume
|
yield volume
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -103,7 +103,7 @@ class CloudController(object):
|
|||||||
result = {}
|
result = {}
|
||||||
for instance in self.instdir.all:
|
for instance in self.instdir.all:
|
||||||
if instance['project_id'] == project_id:
|
if instance['project_id'] == project_id:
|
||||||
line = '%s slots=%d' % (instance['private_dns_name'], node.INSTANCE_TYPES[instance['instance_type']]['vcpus'])
|
line = '%s slots=%d' % (instance['private_dns_name'], computenode.INSTANCE_TYPES[instance['instance_type']]['vcpus'])
|
||||||
if instance['key_name'] in result:
|
if instance['key_name'] in result:
|
||||||
result[instance['key_name']].append(line)
|
result[instance['key_name']].append(line)
|
||||||
else:
|
else:
|
||||||
@@ -296,8 +296,8 @@ class CloudController(object):
|
|||||||
|
|
||||||
@rbac.allow('projectmanager', 'sysadmin')
|
@rbac.allow('projectmanager', 'sysadmin')
|
||||||
def create_volume(self, context, size, **kwargs):
|
def create_volume(self, context, size, **kwargs):
|
||||||
# TODO(vish): refactor this to create the volume object here and tell storage to create it
|
# TODO(vish): refactor this to create the volume object here and tell volumenode to create it
|
||||||
res = rpc.call(FLAGS.storage_topic, {"method": "create_volume",
|
res = rpc.call(FLAGS.volume_topic, {"method": "create_volume",
|
||||||
"args" : {"size": size,
|
"args" : {"size": size,
|
||||||
"user_id": context.user.id,
|
"user_id": context.user.id,
|
||||||
"project_id": context.project.id}})
|
"project_id": context.project.id}})
|
||||||
@@ -331,7 +331,7 @@ class CloudController(object):
|
|||||||
raise exception.NotFound('Instance %s could not be found' % instance_id)
|
raise exception.NotFound('Instance %s could not be found' % instance_id)
|
||||||
|
|
||||||
def _get_volume(self, context, volume_id):
|
def _get_volume(self, context, volume_id):
|
||||||
volume = storage.get_volume(volume_id)
|
volume = volumenode.get_volume(volume_id)
|
||||||
if context.user.is_admin() or volume['project_id'] == context.project.id:
|
if context.user.is_admin() or volume['project_id'] == context.project.id:
|
||||||
return volume
|
return volume
|
||||||
raise exception.NotFound('Volume %s could not be found' % volume_id)
|
raise exception.NotFound('Volume %s could not be found' % volume_id)
|
||||||
@@ -628,8 +628,8 @@ class CloudController(object):
|
|||||||
def delete_volume(self, context, volume_id, **kwargs):
|
def delete_volume(self, context, volume_id, **kwargs):
|
||||||
# TODO: return error if not authorized
|
# TODO: return error if not authorized
|
||||||
volume = self._get_volume(context, volume_id)
|
volume = self._get_volume(context, volume_id)
|
||||||
storage_node = volume['node_name']
|
volume_node = volume['node_name']
|
||||||
rpc.cast('%s.%s' % (FLAGS.storage_topic, storage_node),
|
rpc.cast('%s.%s' % (FLAGS.volume_topic, volume_node),
|
||||||
{"method": "delete_volume",
|
{"method": "delete_volume",
|
||||||
"args" : {"volume_id": volume_id}})
|
"args" : {"volume_id": volume_id}})
|
||||||
return defer.succeed(True)
|
return defer.succeed(True)
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ from nova.compute import model
|
|||||||
from nova.compute import network
|
from nova.compute import network
|
||||||
from nova.endpoint import images
|
from nova.endpoint import images
|
||||||
from nova.endpoint import wsgi
|
from nova.endpoint import wsgi
|
||||||
from nova.volume import storage
|
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ DEFINE_integer('s3_port', 3333, 's3 port')
|
|||||||
DEFINE_string('s3_host', '127.0.0.1', 's3 host')
|
DEFINE_string('s3_host', '127.0.0.1', 's3 host')
|
||||||
#DEFINE_string('cloud_topic', 'cloud', 'the topic clouds listen on')
|
#DEFINE_string('cloud_topic', 'cloud', 'the topic clouds listen on')
|
||||||
DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')
|
DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')
|
||||||
DEFINE_string('storage_topic', 'storage', 'the topic storage nodes listen on')
|
DEFINE_string('volume_topic', 'volume', 'the topic volume nodes listen on')
|
||||||
|
DEFINE_string('network_topic', 'network', 'the topic network nodes listen on')
|
||||||
|
|
||||||
DEFINE_bool('fake_libvirt', False,
|
DEFINE_bool('fake_libvirt', False,
|
||||||
'whether to use a fake libvirt or not')
|
'whether to use a fake libvirt or not')
|
||||||
DEFINE_bool('verbose', False, 'show debug output')
|
DEFINE_bool('verbose', False, 'show debug output')
|
||||||
|
|||||||
103
nova/node.py
Normal file
103
nova/node.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2010 United States Government as represented by the
|
||||||
|
# Administrator of the National Aeronautics and Space Administration.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Generic Node baseclass for all workers that run on hosts
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
from twisted.internet import task
|
||||||
|
from twisted.application import service
|
||||||
|
|
||||||
|
from nova import datastore
|
||||||
|
from nova import flags
|
||||||
|
from nova import rpc
|
||||||
|
from nova.compute import model
|
||||||
|
|
||||||
|
|
||||||
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
flags.DEFINE_integer('report_interval', 10,
|
||||||
|
'seconds between nodes reporting state to cloud',
|
||||||
|
lower_bound=1)
|
||||||
|
|
||||||
|
class Node(object, service.Service):
|
||||||
|
"""Base class for workers that run on hosts"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls,
|
||||||
|
report_interval=None, # defaults to flag
|
||||||
|
bin_name=None, # defaults to basename of executable
|
||||||
|
topic=None): # defaults to basename - "nova-" part
|
||||||
|
"""Instantiates class and passes back application object"""
|
||||||
|
if not report_interval:
|
||||||
|
# NOTE(vish): set here because if it is set to flag in the
|
||||||
|
# parameter list, it wrongly uses the default
|
||||||
|
report_interval = FLAGS.report_interval
|
||||||
|
# NOTE(vish): magic to automatically determine bin_name and topic
|
||||||
|
if not bin_name:
|
||||||
|
bin_name = os.path.basename(inspect.stack()[-1][1])
|
||||||
|
if not topic:
|
||||||
|
topic = bin_name.rpartition("nova-")[2]
|
||||||
|
logging.warn("Starting %s node" % topic)
|
||||||
|
node_instance = cls()
|
||||||
|
|
||||||
|
conn = rpc.Connection.instance()
|
||||||
|
consumer_all = rpc.AdapterConsumer(
|
||||||
|
connection=conn,
|
||||||
|
topic='%s' % topic,
|
||||||
|
proxy=node_instance)
|
||||||
|
|
||||||
|
consumer_node = rpc.AdapterConsumer(
|
||||||
|
connection=conn,
|
||||||
|
topic='%s.%s' % (topic, FLAGS.node_name),
|
||||||
|
proxy=node_instance)
|
||||||
|
|
||||||
|
pulse = task.LoopingCall(node_instance.report_state,
|
||||||
|
FLAGS.node_name,
|
||||||
|
bin_name)
|
||||||
|
pulse.start(interval=report_interval, now=False)
|
||||||
|
|
||||||
|
consumer_all.attach_to_twisted()
|
||||||
|
consumer_node.attach_to_twisted()
|
||||||
|
|
||||||
|
# This is the parent service that twistd will be looking for when it
|
||||||
|
# parses this file, return it so that we can get it into globals below
|
||||||
|
application = service.Application(bin_name)
|
||||||
|
node_instance.setServiceParent(application)
|
||||||
|
return application
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def report_state(self, nodename, daemon):
|
||||||
|
# TODO(termie): make this pattern be more elegant. -todd
|
||||||
|
try:
|
||||||
|
record = model.Daemon(nodename, daemon)
|
||||||
|
record.heartbeat()
|
||||||
|
if getattr(self, "model_disconnected", False):
|
||||||
|
self.model_disconnected = False
|
||||||
|
logging.error("Recovered model server connection!")
|
||||||
|
|
||||||
|
except datastore.ConnectionError, ex:
|
||||||
|
if not getattr(self, "model_disconnected", False):
|
||||||
|
self.model_disconnected = True
|
||||||
|
logging.exception("model server went away")
|
||||||
|
yield
|
||||||
@@ -28,7 +28,7 @@ from nova import flags
|
|||||||
from nova import rpc
|
from nova import rpc
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.auth import users
|
from nova.auth import users
|
||||||
from nova.compute import node
|
from nova.compute import computenode
|
||||||
from nova.endpoint import api
|
from nova.endpoint import api
|
||||||
from nova.endpoint import cloud
|
from nova.endpoint import cloud
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ class CloudTestCase(test.BaseTestCase):
|
|||||||
self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
|
self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
|
||||||
|
|
||||||
# set up a node
|
# set up a node
|
||||||
self.node = node.Node()
|
self.node = computenode.ComputeNode()
|
||||||
self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
|
self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||||
topic=FLAGS.compute_topic,
|
topic=FLAGS.compute_topic,
|
||||||
proxy=self.node)
|
proxy=self.node)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from nova import flags
|
|||||||
from nova import test
|
from nova import test
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.compute import model
|
from nova.compute import model
|
||||||
from nova.compute import node
|
from nova.compute import computenode
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -53,14 +53,14 @@ class InstanceXmlTestCase(test.TrialTestCase):
|
|||||||
# rv = yield first_node.terminate_instance(instance_id)
|
# rv = yield first_node.terminate_instance(instance_id)
|
||||||
|
|
||||||
|
|
||||||
class NodeConnectionTestCase(test.TrialTestCase):
|
class ComputeConnectionTestCase(test.TrialTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
super(NodeConnectionTestCase, self).setUp()
|
super(ComputeConnectionTestCase, self).setUp()
|
||||||
self.flags(fake_libvirt=True,
|
self.flags(fake_libvirt=True,
|
||||||
fake_storage=True,
|
fake_storage=True,
|
||||||
fake_users=True)
|
fake_users=True)
|
||||||
self.node = node.Node()
|
self.node = computenode.ComputeNode()
|
||||||
|
|
||||||
def create_instance(self):
|
def create_instance(self):
|
||||||
instdir = model.InstanceDirectory()
|
instdir = model.InstanceDirectory()
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import mox
|
|
||||||
import StringIO
|
|
||||||
import time
|
|
||||||
from tornado import ioloop
|
|
||||||
from twisted.internet import defer
|
|
||||||
import unittest
|
|
||||||
from xml.etree import ElementTree
|
|
||||||
|
|
||||||
from nova import cloud
|
|
||||||
from nova import exception
|
|
||||||
from nova import flags
|
|
||||||
from nova import node
|
|
||||||
from nova import rpc
|
|
||||||
from nova import test
|
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
|
|
||||||
|
|
||||||
class AdminTestCase(test.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(AdminTestCase, self).setUp()
|
|
||||||
self.flags(fake_libvirt=True,
|
|
||||||
fake_rabbit=True)
|
|
||||||
|
|
||||||
self.conn = rpc.Connection.instance()
|
|
||||||
|
|
||||||
logging.getLogger().setLevel(logging.INFO)
|
|
||||||
|
|
||||||
# set up our cloud
|
|
||||||
self.cloud = cloud.CloudController()
|
|
||||||
self.cloud_consumer = rpc.AdapterConsumer(connection=self.conn,
|
|
||||||
topic=FLAGS.cloud_topic,
|
|
||||||
proxy=self.cloud)
|
|
||||||
self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
|
|
||||||
|
|
||||||
# set up a node
|
|
||||||
self.node = node.Node()
|
|
||||||
self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
|
|
||||||
topic=FLAGS.compute_topic,
|
|
||||||
proxy=self.node)
|
|
||||||
self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
|
|
||||||
|
|
||||||
def test_flush_terminated(self):
|
|
||||||
# Launch an instance
|
|
||||||
|
|
||||||
# Wait until it's running
|
|
||||||
|
|
||||||
# Terminate it
|
|
||||||
|
|
||||||
# Wait until it's terminated
|
|
||||||
|
|
||||||
# Flush terminated nodes
|
|
||||||
|
|
||||||
# ASSERT that it's gone
|
|
||||||
pass
|
|
||||||
@@ -25,7 +25,6 @@ from nova import flags
|
|||||||
from nova import test
|
from nova import test
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.compute import model
|
from nova.compute import model
|
||||||
from nova.compute import node
|
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|||||||
@@ -21,22 +21,22 @@ import logging
|
|||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.compute import node
|
from nova.compute import computenode
|
||||||
from nova.volume import storage
|
from nova.volume import volumenode
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class StorageTestCase(test.TrialTestCase):
|
class VolumeTestCase(test.TrialTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
super(StorageTestCase, self).setUp()
|
super(VolumeTestCase, self).setUp()
|
||||||
self.mynode = node.Node()
|
self.mynode = computenode.ComputeNode()
|
||||||
self.mystorage = None
|
self.mystorage = None
|
||||||
self.flags(fake_libvirt=True,
|
self.flags(fake_libvirt=True,
|
||||||
fake_storage=True)
|
fake_storage=True)
|
||||||
self.mystorage = storage.BlockStore()
|
self.mystorage = volumenode.VolumeNode()
|
||||||
|
|
||||||
def test_run_create_volume(self):
|
def test_run_create_volume(self):
|
||||||
vol_size = '0'
|
vol_size = '0'
|
||||||
@@ -45,11 +45,11 @@ class StorageTestCase(test.TrialTestCase):
|
|||||||
volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
|
volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
|
||||||
# TODO(termie): get_volume returns differently than create_volume
|
# TODO(termie): get_volume returns differently than create_volume
|
||||||
self.assertEqual(volume_id,
|
self.assertEqual(volume_id,
|
||||||
storage.get_volume(volume_id)['volume_id'])
|
volumenode.get_volume(volume_id)['volume_id'])
|
||||||
|
|
||||||
rv = self.mystorage.delete_volume(volume_id)
|
rv = self.mystorage.delete_volume(volume_id)
|
||||||
self.assertRaises(exception.Error,
|
self.assertRaises(exception.Error,
|
||||||
storage.get_volume,
|
volumenode.get_volume,
|
||||||
volume_id)
|
volume_id)
|
||||||
|
|
||||||
def test_too_big_volume(self):
|
def test_too_big_volume(self):
|
||||||
@@ -70,7 +70,7 @@ class StorageTestCase(test.TrialTestCase):
|
|||||||
for i in xrange(total_slots):
|
for i in xrange(total_slots):
|
||||||
vid = self.mystorage.create_volume(vol_size, user_id, project_id)
|
vid = self.mystorage.create_volume(vol_size, user_id, project_id)
|
||||||
vols.append(vid)
|
vols.append(vid)
|
||||||
self.assertRaises(storage.NoMoreVolumes,
|
self.assertRaises(volumenode.NoMoreVolumes,
|
||||||
self.mystorage.create_volume,
|
self.mystorage.create_volume,
|
||||||
vol_size, user_id, project_id)
|
vol_size, user_id, project_id)
|
||||||
for id in vols:
|
for id in vols:
|
||||||
@@ -85,7 +85,7 @@ class StorageTestCase(test.TrialTestCase):
|
|||||||
mountpoint = "/dev/sdf"
|
mountpoint = "/dev/sdf"
|
||||||
volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
|
volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
|
||||||
|
|
||||||
volume_obj = storage.get_volume(volume_id)
|
volume_obj = volumenode.get_volume(volume_id)
|
||||||
volume_obj.start_attach(instance_id, mountpoint)
|
volume_obj.start_attach(instance_id, mountpoint)
|
||||||
rv = yield self.mynode.attach_volume(volume_id,
|
rv = yield self.mynode.attach_volume(volume_id,
|
||||||
instance_id,
|
instance_id,
|
||||||
@@ -100,12 +100,12 @@ class StorageTestCase(test.TrialTestCase):
|
|||||||
volume_id)
|
volume_id)
|
||||||
|
|
||||||
rv = yield self.mystorage.detach_volume(volume_id)
|
rv = yield self.mystorage.detach_volume(volume_id)
|
||||||
volume_obj = storage.get_volume(volume_id)
|
volume_obj = volumenode.get_volume(volume_id)
|
||||||
self.assertEqual(volume_obj['status'], "available")
|
self.assertEqual(volume_obj['status'], "available")
|
||||||
|
|
||||||
rv = self.mystorage.delete_volume(volume_id)
|
rv = self.mystorage.delete_volume(volume_id)
|
||||||
self.assertRaises(exception.Error,
|
self.assertRaises(exception.Error,
|
||||||
storage.get_volume,
|
volumenode.get_volume,
|
||||||
volume_id)
|
volume_id)
|
||||||
|
|
||||||
def test_multi_node(self):
|
def test_multi_node(self):
|
||||||
@@ -32,7 +32,6 @@ from twisted.python import log
|
|||||||
from twisted.python import reflect
|
from twisted.python import reflect
|
||||||
from twisted.python import runtime
|
from twisted.python import runtime
|
||||||
from twisted.python import usage
|
from twisted.python import usage
|
||||||
import UserDict
|
|
||||||
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
|
|
||||||
@@ -161,6 +160,13 @@ def WrapTwistedOptions(wrapped):
|
|||||||
except (AttributeError, KeyError):
|
except (AttributeError, KeyError):
|
||||||
self._data[key] = value
|
self._data[key] = value
|
||||||
|
|
||||||
|
def get(self, key, default):
|
||||||
|
key = key.replace('-', '_')
|
||||||
|
try:
|
||||||
|
return getattr(FLAGS, key)
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
self._data.get(key, default)
|
||||||
|
|
||||||
return TwistedOptionsToFlags
|
return TwistedOptionsToFlags
|
||||||
|
|
||||||
|
|
||||||
@@ -210,8 +216,12 @@ def serve(filename):
|
|||||||
elif FLAGS.pidfile.endswith('twistd.pid'):
|
elif FLAGS.pidfile.endswith('twistd.pid'):
|
||||||
FLAGS.pidfile = FLAGS.pidfile.replace('twistd.pid', '%s.pid' % name)
|
FLAGS.pidfile = FLAGS.pidfile.replace('twistd.pid', '%s.pid' % name)
|
||||||
|
|
||||||
|
print FLAGS.logfile
|
||||||
if not FLAGS.logfile:
|
if not FLAGS.logfile:
|
||||||
FLAGS.logfile = '%s.log' % name
|
FLAGS.logfile = '%s.log' % name
|
||||||
|
elif FLAGS.logfile.endswith('twistd.log'):
|
||||||
|
FLAGS.logfile = FLAGS.logfile.replace('twistd.log', '%s.log' % name)
|
||||||
|
print FLAGS.logfile
|
||||||
|
|
||||||
action = 'start'
|
action = 'start'
|
||||||
if len(argv) > 1:
|
if len(argv) > 1:
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ from nova import twistd
|
|||||||
from nova.tests.access_unittest import *
|
from nova.tests.access_unittest import *
|
||||||
from nova.tests.api_unittest import *
|
from nova.tests.api_unittest import *
|
||||||
from nova.tests.cloud_unittest import *
|
from nova.tests.cloud_unittest import *
|
||||||
|
from nova.tests.compute_unittest import *
|
||||||
from nova.tests.model_unittest import *
|
from nova.tests.model_unittest import *
|
||||||
from nova.tests.network_unittest import *
|
from nova.tests.network_unittest import *
|
||||||
from nova.tests.node_unittest import *
|
|
||||||
from nova.tests.objectstore_unittest import *
|
from nova.tests.objectstore_unittest import *
|
||||||
from nova.tests.process_unittest import *
|
from nova.tests.process_unittest import *
|
||||||
from nova.tests.storage_unittest import *
|
|
||||||
from nova.tests.users_unittest import *
|
from nova.tests.users_unittest import *
|
||||||
from nova.tests.validator_unittest import *
|
from nova.tests.validator_unittest import *
|
||||||
|
from nova.tests.volume_unittest import *
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|||||||
Reference in New Issue
Block a user