Indentaion fixes all over the place
This commit is contained in:
parent
b5af546ced
commit
d011fb5f44
@ -22,8 +22,7 @@ from reddwarf.common import wsgi
|
||||
from reddwarf.versions import VersionsController
|
||||
from reddwarf.flavor.service import FlavorController
|
||||
from reddwarf.instance.service import InstanceController
|
||||
from reddwarf.extensions.mgmt.host.instance.service import (
|
||||
HostInstanceController)
|
||||
from reddwarf.extensions.mgmt.host.instance import service as hostservice
|
||||
|
||||
|
||||
class API(wsgi.Router):
|
||||
@ -51,7 +50,8 @@ class API(wsgi.Router):
|
||||
mapper.resource("flavor", path, controller=flavor_resource)
|
||||
|
||||
def _host_instance_router(self, mapper):
|
||||
host_instance_resource = HostInstanceController().create_resource()
|
||||
host_controller = hostservice.HostInstanceController()
|
||||
host_instance_resource = host_controller.create_resource()
|
||||
path = "/{tenant_id}/mgmt/hosts/{host_id}/instances"
|
||||
mapper.resource("hostinstance", path,
|
||||
controller=host_instance_resource,
|
||||
|
@ -32,7 +32,7 @@ class AuthorizationMiddleware(wsgi.Middleware):
|
||||
self.auth_providers = auth_providers
|
||||
LOG.debug(_("Auth middleware providers: %s") % auth_providers)
|
||||
super(AuthorizationMiddleware, self).__init__(application,
|
||||
**local_config)
|
||||
**local_config)
|
||||
|
||||
def process_request(self, request):
|
||||
roles = request.headers.get('X_ROLE', '').split(',')
|
||||
@ -46,9 +46,8 @@ class AuthorizationMiddleware(wsgi.Middleware):
|
||||
def factory(cls, global_config, **local_config):
|
||||
def _factory(app):
|
||||
LOG.debug(_("Created auth middleware with config: %s") %
|
||||
local_config)
|
||||
return cls(app, [TenantBasedAuth()],
|
||||
**local_config)
|
||||
local_config)
|
||||
return cls(app, [TenantBasedAuth()], **local_config)
|
||||
return _factory
|
||||
|
||||
|
||||
@ -61,13 +60,12 @@ class TenantBasedAuth(object):
|
||||
def authorize(self, request, tenant_id, roles):
|
||||
match_for_tenant = self.tenant_scoped_url.match(request.path_info)
|
||||
if (match_for_tenant and
|
||||
tenant_id == match_for_tenant.group('tenant_id')):
|
||||
tenant_id == match_for_tenant.group('tenant_id')):
|
||||
LOG.debug(_("Authorized tenant '%(tenant_id)s' request: "
|
||||
"%(request)s") % locals())
|
||||
return True
|
||||
msg = _("User with tenant id %s cannot access this resource") \
|
||||
% tenant_id
|
||||
LOG.debug(msg)
|
||||
msg = _("User with tenant id %s cannot access this resource")
|
||||
LOG.debug(msg % tenant_id)
|
||||
raise webob.exc.HTTPForbidden(msg)
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ class Config(object):
|
||||
config_file = openstack_config.find_config_file(*args)
|
||||
if not config_file:
|
||||
raise RuntimeError("Unable to locate any configuration file. "
|
||||
"Cannot load application %s" % app_name)
|
||||
"Cannot load application %s" % app_name)
|
||||
# Now take the conf file values and append them to the current conf
|
||||
with open(config_file, 'r') as conf:
|
||||
for line in conf.readlines():
|
||||
@ -76,7 +76,7 @@ class Config(object):
|
||||
config_file = openstack_config.find_config_file(*args)
|
||||
if not config_file:
|
||||
raise RuntimeError("Unable to locate any configuration file. "
|
||||
"Cannot load application %s" % app_name)
|
||||
"Cannot load application %s" % app_name)
|
||||
with open(config_file, 'a') as conf:
|
||||
for k, v in kwargs.items():
|
||||
# Start with newline to be sure its on a new line
|
||||
|
@ -43,6 +43,6 @@ def save_and_reraise_exception():
|
||||
yield
|
||||
except Exception:
|
||||
logging.error('Original exception being dropped: %s' %
|
||||
(traceback.format_exception(type_, value, tb)))
|
||||
(traceback.format_exception(type_, value, tb)))
|
||||
raise
|
||||
raise type_, value, tb
|
||||
|
@ -31,8 +31,8 @@ ResourceExtension = extensions.ResourceExtension
|
||||
class ReddwarfExtensionMiddleware(extensions.ExtensionMiddleware):
|
||||
|
||||
def __init__(self, application, config, ext_mgr=None):
|
||||
ext_mgr = ext_mgr or ExtensionManager(
|
||||
config['api_extensions_path'])
|
||||
ext_mgr = (ext_mgr or
|
||||
ExtensionManager(config['api_extensions_path']))
|
||||
mapper = routes.Mapper()
|
||||
|
||||
# extended resources
|
||||
@ -60,7 +60,7 @@ class ReddwarfExtensionMiddleware(extensions.ExtensionMiddleware):
|
||||
|
||||
# extended actions
|
||||
action_resources = self._action_ext_resources(application, ext_mgr,
|
||||
mapper)
|
||||
mapper)
|
||||
for action in ext_mgr.get_actions():
|
||||
LOG.debug(_('Extended action: %s'), action.action_name)
|
||||
resource = action_resources[action.collection]
|
||||
|
@ -38,7 +38,7 @@ class ManagerAPI(object):
|
||||
def _real_cast(self, method_name, **kwargs):
|
||||
try:
|
||||
rpc.cast(self.context, self._get_routing_key(),
|
||||
{"method": method_name, "args": kwargs})
|
||||
{"method": method_name, "args": kwargs})
|
||||
except Exception as e:
|
||||
LOG.error(e)
|
||||
raise exception.TaskManagerError(original_message=str(e))
|
||||
|
@ -39,9 +39,10 @@ class PaginatedDataView(object):
|
||||
return []
|
||||
app_url = AppUrl(self.current_page_url)
|
||||
next_url = app_url.change_query_params(marker=self.next_page_marker)
|
||||
next_link = {'rel': 'next',
|
||||
'href': str(next_url),
|
||||
}
|
||||
next_link = {
|
||||
'rel': 'next',
|
||||
'href': str(next_url),
|
||||
}
|
||||
return [next_link]
|
||||
|
||||
|
||||
|
@ -36,8 +36,8 @@ def create_nova_client(context):
|
||||
COMPUTE_URL = CONFIG.get('nova_compute_url', 'http://localhost:8774/v2')
|
||||
PROXY_AUTH_URL = CONFIG.get('reddwarf_auth_url',
|
||||
'http://0.0.0.0:5000/v2.0')
|
||||
client = Client(context.user, context.auth_tok,
|
||||
project_id=context.tenant, auth_url=PROXY_AUTH_URL)
|
||||
client = Client(context.user, context.auth_tok, project_id=context.tenant,
|
||||
auth_url=PROXY_AUTH_URL)
|
||||
client.client.auth_token = context.auth_tok
|
||||
client.client.management_url = "%s/%s/" % (COMPUTE_URL, context.tenant)
|
||||
|
||||
@ -51,7 +51,7 @@ def create_nova_volume_client(context):
|
||||
PROXY_AUTH_URL = CONFIG.get('reddwarf_auth_url',
|
||||
'http://0.0.0.0:5000/v2.0')
|
||||
client = Client(context.user, context.auth_tok,
|
||||
project_id=context.tenant, auth_url=PROXY_AUTH_URL)
|
||||
project_id=context.tenant, auth_url=PROXY_AUTH_URL)
|
||||
client.client.auth_token = context.auth_tok
|
||||
client.client.management_url = "%s/%s/" % (VOLUME_URL, context.tenant)
|
||||
|
||||
|
@ -113,7 +113,7 @@ class Service(object):
|
||||
def start(self):
|
||||
vcs_string = version.version_string_with_vcs()
|
||||
LOG.info(_('Starting %(topic)s node (version %(vcs_string)s)'),
|
||||
{'topic': self.topic, 'vcs_string': vcs_string})
|
||||
{'topic': self.topic, 'vcs_string': vcs_string})
|
||||
|
||||
self.conn = rpc.create_connection(new=True)
|
||||
LOG.debug(_("Creating Consumer connection for Service %s") %
|
||||
@ -171,8 +171,8 @@ class Service(object):
|
||||
report_interval = config.Config.get('report_interval', 10)
|
||||
if not periodic_interval:
|
||||
periodic_interval = config.Config.get('periodic_interval', 60)
|
||||
service_obj = cls(host, binary, topic, manager,
|
||||
report_interval, periodic_interval)
|
||||
service_obj = cls(host, binary, topic, manager, report_interval,
|
||||
periodic_interval)
|
||||
|
||||
return service_obj
|
||||
|
||||
|
@ -49,26 +49,28 @@ LOG = logging.getLogger('reddwarf.common.wsgi')
|
||||
XMLNS = 'http://docs.openstack.org/database/api/v1.0'
|
||||
CUSTOM_PLURALS_METADATA = {'databases': '', 'users': ''}
|
||||
CUSTOM_SERIALIZER_METADATA = {
|
||||
'instance': {'status': '',
|
||||
'hostname': '',
|
||||
'id': '',
|
||||
'name': '',
|
||||
'created': '',
|
||||
'updated': '',
|
||||
'host': '',
|
||||
'server_id': '',
|
||||
#mgmt/instance
|
||||
'local_id': '',
|
||||
'task_description': '',
|
||||
'deleted': '',
|
||||
'deleted_at': '',
|
||||
'tenant_id': '',
|
||||
},
|
||||
'volume': {'size': '',
|
||||
'used': '',
|
||||
#mgmt/instance
|
||||
'id': '',
|
||||
},
|
||||
'instance': {
|
||||
'status': '',
|
||||
'hostname': '',
|
||||
'id': '',
|
||||
'name': '',
|
||||
'created': '',
|
||||
'updated': '',
|
||||
'host': '',
|
||||
'server_id': '',
|
||||
#mgmt/instance
|
||||
'local_id': '',
|
||||
'task_description': '',
|
||||
'deleted': '',
|
||||
'deleted_at': '',
|
||||
'tenant_id': '',
|
||||
},
|
||||
'volume': {
|
||||
'size': '',
|
||||
'used': '',
|
||||
#mgmt/instance
|
||||
'id': '',
|
||||
},
|
||||
'flavor': {'id': '', 'ram': '', 'name': ''},
|
||||
'link': {'href': '', 'rel': ''},
|
||||
'database': {'name': ''},
|
||||
@ -76,7 +78,7 @@ CUSTOM_SERIALIZER_METADATA = {
|
||||
'account': {'id': ''},
|
||||
# mgmt/host
|
||||
'host': {'instanceCount': '', 'name': '', 'usedRAM': '', 'totalRAM': '',
|
||||
'percentUsed': ''},
|
||||
'percentUsed': ''},
|
||||
# mgmt/storage
|
||||
'capacity': {'available': '', 'total': ''},
|
||||
'provision': {'available': '', 'total': '', 'percent': ''},
|
||||
@ -87,7 +89,7 @@ CUSTOM_SERIALIZER_METADATA = {
|
||||
'guest_status': {'state_description': ''},
|
||||
#mgmt/instance/diagnostics
|
||||
'diagnostics': {'vmHwm': '', 'vmPeak': '', 'vmSize': '', 'threads': '',
|
||||
'version': '', 'vmRss': '', 'fdSize': ''},
|
||||
'version': '', 'vmRss': '', 'fdSize': ''},
|
||||
#mgmt/instance/root
|
||||
'root_history': {'enabled': '', 'id': '', 'user': ''},
|
||||
}
|
||||
@ -134,11 +136,12 @@ class Request(openstack_wsgi.Request):
|
||||
if format in ['json', 'xml']:
|
||||
return 'application/{0}'.format(parts[1])
|
||||
|
||||
ctypes = {'application/vnd.openstack.reddwarf+json':
|
||||
"application/json",
|
||||
'application/vnd.openstack.reddwarf+xml': "application/xml",
|
||||
'application/json': "application/json",
|
||||
'application/xml': "application/xml"}
|
||||
ctypes = {
|
||||
'application/vnd.openstack.reddwarf+json': "application/json",
|
||||
'application/vnd.openstack.reddwarf+xml': "application/xml",
|
||||
'application/json': "application/json",
|
||||
'application/xml': "application/xml",
|
||||
}
|
||||
bm = self.accept.best_match(ctypes.keys())
|
||||
|
||||
return ctypes.get(bm, 'application/json')
|
||||
@ -182,7 +185,7 @@ class Result(object):
|
||||
|
||||
"""
|
||||
if (serialization_type == "application/xml" and
|
||||
hasattr(self._data, "data_for_xml")):
|
||||
hasattr(self._data, "data_for_xml")):
|
||||
return self._data.data_for_xml()
|
||||
if hasattr(self._data, "data_for_json"):
|
||||
return self._data.data_for_json()
|
||||
@ -205,7 +208,8 @@ class Resource(openstack_wsgi.Resource):
|
||||
if getattr(self.controller, action, None) is None:
|
||||
return Fault(webob.exc.HTTPNotFound())
|
||||
try:
|
||||
result = super(Resource, self).execute_action(action,
|
||||
result = super(Resource, self).execute_action(
|
||||
action,
|
||||
request,
|
||||
**action_args)
|
||||
if type(result) is dict:
|
||||
@ -221,12 +225,13 @@ class Resource(openstack_wsgi.Resource):
|
||||
return Fault(http_error)
|
||||
except Exception as error:
|
||||
LOG.exception(error)
|
||||
return Fault(webob.exc.HTTPInternalServerError(str(error),
|
||||
return Fault(webob.exc.HTTPInternalServerError(
|
||||
str(error),
|
||||
request=request))
|
||||
|
||||
def _get_http_error(self, error):
|
||||
return self.model_exception_map.get(type(error),
|
||||
webob.exc.HTTPBadRequest)
|
||||
webob.exc.HTTPBadRequest)
|
||||
|
||||
def _invert_dict_list(self, exception_dict):
|
||||
"""Flattens values of keys and inverts keys and values.
|
||||
@ -268,10 +273,10 @@ class Controller(object):
|
||||
exception_map = {
|
||||
webob.exc.HTTPUnprocessableEntity: [
|
||||
exception.UnprocessableEntity,
|
||||
],
|
||||
],
|
||||
webob.exc.HTTPUnauthorized: [
|
||||
exception.Forbidden,
|
||||
],
|
||||
],
|
||||
webob.exc.HTTPBadRequest: [
|
||||
exception.InvalidModelError,
|
||||
exception.BadRequest,
|
||||
@ -279,35 +284,35 @@ class Controller(object):
|
||||
exception.BadValue,
|
||||
exception.DatabaseAlreadyExists,
|
||||
exception.UserAlreadyExists,
|
||||
],
|
||||
],
|
||||
webob.exc.HTTPNotFound: [
|
||||
exception.NotFound,
|
||||
exception.ComputeInstanceNotFound,
|
||||
exception.ModelNotFoundError,
|
||||
],
|
||||
webob.exc.HTTPConflict: [
|
||||
],
|
||||
],
|
||||
webob.exc.HTTPConflict: [],
|
||||
webob.exc.HTTPRequestEntityTooLarge: [
|
||||
exception.OverLimit,
|
||||
exception.QuotaExceeded,
|
||||
exception.VolumeQuotaExceeded,
|
||||
],
|
||||
],
|
||||
webob.exc.HTTPServerError: [
|
||||
exception.VolumeCreationFailure,
|
||||
exception.UpdateGuestError,
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.add_addresses = utils.bool_from_string(
|
||||
config.Config.get('add_addresses', 'False'))
|
||||
config.Config.get('add_addresses', 'False'))
|
||||
self.add_volumes = utils.bool_from_string(
|
||||
config.Config.get('reddwarf_volume_support', 'False'))
|
||||
config.Config.get('reddwarf_volume_support', 'False'))
|
||||
|
||||
def create_resource(self):
|
||||
serializer = ReddwarfResponseSerializer(
|
||||
body_serializers={'application/xml': ReddwarfXMLDictSerializer()})
|
||||
return Resource(self,
|
||||
return Resource(
|
||||
self,
|
||||
ReddwarfRequestDeserializer(),
|
||||
serializer,
|
||||
self.exception_map)
|
||||
@ -328,9 +333,10 @@ class ReddwarfRequestDeserializer(RequestDeserializer):
|
||||
|
||||
def __init__(self, body_deserializers=None, headers_deserializer=None,
|
||||
supported_content_types=None):
|
||||
super(ReddwarfRequestDeserializer, self).__init__(body_deserializers,
|
||||
headers_deserializer,
|
||||
supported_content_types)
|
||||
super(ReddwarfRequestDeserializer, self).__init__(
|
||||
body_deserializers,
|
||||
headers_deserializer,
|
||||
supported_content_types)
|
||||
|
||||
self.body_deserializers['application/xml'] = ReddwarfXMLDeserializer()
|
||||
|
||||
@ -392,7 +398,8 @@ class ReddwarfXMLDictSerializer(openstack_wsgi.XMLDictSerializer):
|
||||
metadata['attributes'] = CUSTOM_SERIALIZER_METADATA
|
||||
if hasattr(data, "to_xml"):
|
||||
return data.to_xml()
|
||||
return super(ReddwarfXMLDictSerializer, self)._to_xml_node(doc,
|
||||
return super(ReddwarfXMLDictSerializer, self)._to_xml_node(
|
||||
doc,
|
||||
metadata,
|
||||
nodename,
|
||||
data)
|
||||
@ -410,13 +417,15 @@ class ReddwarfResponseSerializer(openstack_wsgi.ResponseSerializer):
|
||||
"""
|
||||
if isinstance(data, Result):
|
||||
data = data.data(content_type)
|
||||
super(ReddwarfResponseSerializer, self).serialize_body(response,
|
||||
super(ReddwarfResponseSerializer, self).serialize_body(
|
||||
response,
|
||||
data,
|
||||
content_type,
|
||||
action)
|
||||
|
||||
def serialize_headers(self, response, data, action):
|
||||
super(ReddwarfResponseSerializer, self).serialize_headers(response,
|
||||
super(ReddwarfResponseSerializer, self).serialize_headers(
|
||||
response,
|
||||
data,
|
||||
action)
|
||||
if isinstance(data, Result):
|
||||
@ -473,7 +482,7 @@ class Fault(webob.exc.HTTPException):
|
||||
fault_data = {
|
||||
fault_name: {
|
||||
'code': self.wrapped_exc.status_int,
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.wrapped_exc.detail:
|
||||
fault_data[fault_name]['message'] = self.wrapped_exc.detail
|
||||
@ -486,7 +495,7 @@ class Fault(webob.exc.HTTPException):
|
||||
serializer = {
|
||||
'application/xml': openstack_wsgi.XMLDictSerializer(metadata),
|
||||
'application/json': openstack_wsgi.JSONDictSerializer(),
|
||||
}[content_type]
|
||||
}[content_type]
|
||||
|
||||
self.wrapped_exc.body = serializer.serialize(fault_data, content_type)
|
||||
self.wrapped_exc.content_type = content_type
|
||||
@ -526,7 +535,7 @@ class ContextMiddleware(openstack_wsgi.Middleware):
|
||||
def factory(cls, global_config, **local_config):
|
||||
def _factory(app):
|
||||
LOG.debug(_("Created context middleware with config: %s") %
|
||||
local_config)
|
||||
local_config)
|
||||
return cls(app)
|
||||
return _factory
|
||||
|
||||
|
@ -21,8 +21,9 @@ from reddwarf.common import utils
|
||||
from reddwarf.common import config
|
||||
|
||||
|
||||
db_api = utils.import_object(config.Config.get("db_api_implementation",
|
||||
"reddwarf.db.sqlalchemy.api"))
|
||||
db_api = utils.import_object(
|
||||
config.Config.get("db_api_implementation",
|
||||
"reddwarf.db.sqlalchemy.api"))
|
||||
|
||||
|
||||
class Query(object):
|
||||
@ -49,13 +50,14 @@ class Query(object):
|
||||
|
||||
def update(self, **values):
|
||||
db_api.update_all(self._query_func, self._model, self._conditions,
|
||||
values)
|
||||
values)
|
||||
|
||||
def delete(self):
|
||||
db_api.delete_all(self._query_func, self._model, **self._conditions)
|
||||
|
||||
def limit(self, limit=200, marker=None, marker_column=None):
|
||||
return db_api.find_all_by_limit(self._query_func,
|
||||
return db_api.find_all_by_limit(
|
||||
self._query_func,
|
||||
self._model,
|
||||
self._conditions,
|
||||
limit=limit,
|
||||
@ -88,10 +90,12 @@ def add_options(parser):
|
||||
help_text = ("The following configuration options are specific to the "
|
||||
"Reddwarf database.")
|
||||
|
||||
group = optparse.OptionGroup(parser,
|
||||
group = optparse.OptionGroup(
|
||||
parser,
|
||||
"Registry Database Options",
|
||||
help_text)
|
||||
group.add_option('--sql-connection',
|
||||
group.add_option(
|
||||
'--sql-connection',
|
||||
metavar="CONNECTION",
|
||||
default=None,
|
||||
help="A valid SQLAlchemy connection string for the "
|
||||
|
@ -32,17 +32,19 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
instances = Table('instances', meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('created', DateTime()),
|
||||
Column('updated', DateTime()),
|
||||
Column('name', String(255)),
|
||||
Column('hostname', String(255)),
|
||||
Column('compute_instance_id', String(36)),
|
||||
Column('task_id', Integer()),
|
||||
Column('task_description', String(32)),
|
||||
Column('task_start_time', DateTime()),
|
||||
Column('volume_id', String(36)))
|
||||
instances = Table(
|
||||
'instances',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('created', DateTime()),
|
||||
Column('updated', DateTime()),
|
||||
Column('name', String(255)),
|
||||
Column('hostname', String(255)),
|
||||
Column('compute_instance_id', String(36)),
|
||||
Column('task_id', Integer()),
|
||||
Column('task_description', String(32)),
|
||||
Column('task_start_time', DateTime()),
|
||||
Column('volume_id', String(36)))
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
|
@ -32,7 +32,9 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
service_images = Table('service_images', meta,
|
||||
service_images = Table(
|
||||
'service_images',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('service_name', String(255)),
|
||||
Column('image_id', String(255)))
|
||||
|
@ -32,7 +32,9 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
service_statuses = Table('service_statuses', meta,
|
||||
service_statuses = Table(
|
||||
'service_statuses',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('instance_id', String(36), nullable=False),
|
||||
Column('status_id', Integer(), nullable=False),
|
||||
|
@ -29,11 +29,13 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
root_enabled_history = Table('root_enabled_history', meta,
|
||||
root_enabled_history = Table(
|
||||
'root_enabled_history',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('user', String(length=255)),
|
||||
Column('created', DateTime()),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
|
@ -32,7 +32,9 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
agent_heartbeats = Table('agent_heartbeats', meta,
|
||||
agent_heartbeats = Table(
|
||||
'agent_heartbeats',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('instance_id', String(36), nullable=False),
|
||||
Column('updated_at', DateTime()))
|
||||
|
@ -29,9 +29,10 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import String
|
||||
meta = MetaData()
|
||||
|
||||
|
||||
dns_records = Table('dns_records', meta,
|
||||
Column('name', String(length=255), primary_key=True),
|
||||
Column('record_id', String(length=64)))
|
||||
dns_records = Table(
|
||||
'dns_records', meta,
|
||||
Column('name', String(length=255), primary_key=True),
|
||||
Column('record_id', String(length=64)))
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
|
@ -31,7 +31,9 @@ from reddwarf.db.sqlalchemy.migrate_repo.schema import Table
|
||||
meta = MetaData()
|
||||
|
||||
|
||||
usage_events = Table('usage_events', meta,
|
||||
usage_events = Table(
|
||||
'usage_events',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column('instance_name', String(36)),
|
||||
Column('tenant_id', String(36)),
|
||||
|
@ -127,8 +127,9 @@ def db_sync(options, version=None, repo_path=None):
|
||||
def get_migrate_repo_path(repo_path=None):
|
||||
"""Get the path for the migrate repository."""
|
||||
|
||||
default_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
||||
'migrate_repo')
|
||||
default_path = os.path.join(
|
||||
os.path.abspath(os.path.dirname(__file__)),
|
||||
'migrate_repo')
|
||||
repo_path = repo_path or default_path
|
||||
assert os.path.exists(repo_path)
|
||||
return repo_path
|
||||
|
@ -90,9 +90,11 @@ class DnsEntry(object):
|
||||
self.ttl = ttl
|
||||
|
||||
def __repr__(self):
|
||||
return 'DnsEntry(name="%s", content="%s", type="%s", ' \
|
||||
'ttl=%s, priority=%s, dns_zone=%s)' % (self.name, self.content,
|
||||
self.type, self.ttl, self.priority, self.dns_zone)
|
||||
msg = ('DnsEntry(name="%s", content="%s", type="%s", '
|
||||
'ttl=%s, priority=%s, dns_zone=%s)')
|
||||
params = (self.name, self.content, self.type, self.ttl, self.priority,
|
||||
self.dns_zone)
|
||||
return msg % params
|
||||
|
||||
def __str__(self):
|
||||
return "{ name:%s, content:%s, type:%s, zone:%s }" % \
|
||||
|
@ -32,15 +32,16 @@ class DnsManager(object):
|
||||
def __init__(self, dns_driver=None, dns_instance_entry_factory=None,
|
||||
*args, **kwargs):
|
||||
if not dns_driver:
|
||||
dns_driver = config.Config.get("dns_driver",
|
||||
"reddwarf.dns.driver.DnsDriver")
|
||||
dns_driver = config.Config.get(
|
||||
"dns_driver",
|
||||
"reddwarf.dns.driver.DnsDriver")
|
||||
dns_driver = utils.import_object(dns_driver)
|
||||
self.driver = dns_driver()
|
||||
|
||||
if not dns_instance_entry_factory:
|
||||
dns_instance_entry_factory = config.Config.get(
|
||||
'dns_instance_entry_factory',
|
||||
'reddwarf.dns.driver.DnsInstanceEntryFactory')
|
||||
'dns_instance_entry_factory',
|
||||
'reddwarf.dns.driver.DnsInstanceEntryFactory')
|
||||
entry_factory = utils.import_object(dns_instance_entry_factory)
|
||||
self.entry_factory = entry_factory()
|
||||
|
||||
|
@ -31,7 +31,7 @@ LOG = logging.getLogger(__name__)
|
||||
def persisted_models():
|
||||
return {
|
||||
'dns_records': DnsRecord,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DnsRecord(ModelBase):
|
||||
|
@ -65,17 +65,17 @@ class EntryToRecordConverter(object):
|
||||
|
||||
def record_to_entry(self, record, dns_zone):
|
||||
entry_name = record.name
|
||||
return DnsEntry(name=entry_name, content=record.data, type=record.type,
|
||||
ttl=record.ttl, dns_zone=dns_zone)
|
||||
return DnsEntry(name=entry_name, content=record.data,
|
||||
type=record.type, ttl=record.ttl, dns_zone=dns_zone)
|
||||
|
||||
|
||||
def create_client_with_flag_values():
|
||||
"""Creates a RS DNSaaS client using the Flag values."""
|
||||
if DNS_MANAGEMENT_BASE_URL == None:
|
||||
if DNS_MANAGEMENT_BASE_URL is None:
|
||||
raise RuntimeError("Missing flag value for dns_management_base_url.")
|
||||
return DNSaas(DNS_ACCOUNT_ID, DNS_USERNAME, DNS_PASSKEY,
|
||||
auth_url=DNS_AUTH_URL,
|
||||
management_base_url=DNS_MANAGEMENT_BASE_URL)
|
||||
auth_url=DNS_AUTH_URL,
|
||||
management_base_url=DNS_MANAGEMENT_BASE_URL)
|
||||
|
||||
|
||||
def find_default_zone(dns_client, raise_if_zone_missing=True):
|
||||
@ -96,9 +96,10 @@ def find_default_zone(dns_client, raise_if_zone_missing=True):
|
||||
pass
|
||||
if not raise_if_zone_missing:
|
||||
return RsDnsZone(id=None, name=domain_name)
|
||||
raise RuntimeError("The dns_domain_name from the FLAG values (%s) "
|
||||
"does not exist! account_id=%s, username=%s, LIST=%s"
|
||||
% (domain_name, DNS_ACCOUNT_ID, DNS_USERNAME, domains))
|
||||
msg = ("The dns_domain_name from the FLAG values (%s) "
|
||||
"does not exist! account_id=%s, username=%s, LIST=%s")
|
||||
params = (domain_name, DNS_ACCOUNT_ID, DNS_USERNAME, domains)
|
||||
raise RuntimeError(msg % params)
|
||||
|
||||
|
||||
class RsDnsDriver(object):
|
||||
@ -108,20 +109,21 @@ class RsDnsDriver(object):
|
||||
self.dns_client = create_client_with_flag_values()
|
||||
self.dns_client.authenticate()
|
||||
self.default_dns_zone = RsDnsZone(id=DNS_DOMAIN_ID,
|
||||
name=DNS_DOMAIN_NAME)
|
||||
name=DNS_DOMAIN_NAME)
|
||||
self.converter = EntryToRecordConverter(self.default_dns_zone)
|
||||
if DNS_TTL < 300:
|
||||
raise Exception("TTL value '--dns_ttl=%s' should be greater than"\
|
||||
" 300" % DNS_TTL)
|
||||
msg = "TTL value '--dns_ttl=%s' should be greater than 300"
|
||||
raise Exception(msg % DNS_TTL)
|
||||
|
||||
def create_entry(self, entry):
|
||||
dns_zone = entry.dns_zone or self.default_dns_zone
|
||||
if dns_zone.id == None:
|
||||
if dns_zone.id is None:
|
||||
raise TypeError("The entry's dns_zone must have an ID specified.")
|
||||
name = entry.name # + "." + dns_zone.name
|
||||
LOG.debug("Going to create RSDNS entry %s." % name)
|
||||
try:
|
||||
future = self.dns_client.records.create(domain=dns_zone.id,
|
||||
future = self.dns_client.records.create(
|
||||
domain=dns_zone.id,
|
||||
record_name=name,
|
||||
record_data=entry.content,
|
||||
record_type=entry.type,
|
||||
@ -151,7 +153,8 @@ class RsDnsDriver(object):
|
||||
dns_zone = dns_zone or self.default_dns_zone
|
||||
long_name = name
|
||||
db_record = DnsRecord.find_by(name=name)
|
||||
record = self.dns_client.records.get(domain_id=dns_zone.id,
|
||||
record = self.dns_client.records.get(
|
||||
domain_id=dns_zone.id,
|
||||
record_id=db_record.record_id)
|
||||
if record.name != name or record.type != 'A':
|
||||
LOG.error("Tried to delete DNS record with name=%s, id=%s, but the"
|
||||
@ -159,14 +162,16 @@ class RsDnsDriver(object):
|
||||
"type %s." % (name, db_record.id, record.name,
|
||||
record.type))
|
||||
raise exception.DnsRecordNotFound(name)
|
||||
self.dns_client.records.delete(domain_id=dns_zone.id,
|
||||
self.dns_client.records.delete(
|
||||
domain_id=dns_zone.id,
|
||||
record_id=record.id)
|
||||
db_record.delete()
|
||||
|
||||
def get_entries(self, name=None, content=None, dns_zone=None):
|
||||
dns_zone = dns_zone or self.defaucreate_entrylt_dns_zone
|
||||
long_name = name # self.converter.name_to_long_name(name)
|
||||
records = self.dns_client.records.list(domain_id=dns_zone.id,
|
||||
records = self.dns_client.records.list(
|
||||
domain_id=dns_zone.id,
|
||||
record_name=long_name,
|
||||
record_address=content)
|
||||
return [self.converter.record_to_entry(record, dns_zone)
|
||||
@ -196,14 +201,14 @@ class RsDnsInstanceEntryFactory(object):
|
||||
def __init__(self, dns_domain_id=None):
|
||||
dns_domain_id = dns_domain_id or DNS_DOMAIN_ID
|
||||
self.default_dns_zone = RsDnsZone(id=dns_domain_id,
|
||||
name=DNS_DOMAIN_NAME)
|
||||
name=DNS_DOMAIN_NAME)
|
||||
|
||||
def create_entry(self, instance_id):
|
||||
id = instance_id
|
||||
hostname = ("%s.%s" % (hashlib.sha1(id).hexdigest(),
|
||||
self.default_dns_zone.name))
|
||||
return DnsEntry(name=hostname, content=None, type="A",
|
||||
ttl=DNS_TTL, dns_zone=self.default_dns_zone)
|
||||
return DnsEntry(name=hostname, content=None, type="A", ttl=DNS_TTL,
|
||||
dns_zone=self.default_dns_zone)
|
||||
|
||||
|
||||
class RsDnsZone(object):
|
||||
@ -213,8 +218,9 @@ class RsDnsZone(object):
|
||||
self.id = id
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, RsDnsZone) and\
|
||||
self.name == other.name and self.id == other.id
|
||||
return (isinstance(other, RsDnsZone) and
|
||||
self.name == other.name and
|
||||
self.id == other.id)
|
||||
|
||||
def __str__(self):
|
||||
return "%s:%s" % (self.id, self.name)
|
||||
|
@ -45,10 +45,11 @@ class Account(extensions.ExtensionsDescriptor):
|
||||
serializer = wsgi.ReddwarfResponseSerializer(
|
||||
body_serializers={'application/xml':
|
||||
wsgi.ReddwarfXMLDictSerializer()})
|
||||
resource = extensions.ResourceExtension('{tenant_id}/mgmt/accounts',
|
||||
service.AccountController(),
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer)
|
||||
resource = extensions.ResourceExtension(
|
||||
'{tenant_id}/mgmt/accounts',
|
||||
service.AccountController(),
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer)
|
||||
resources.append(resource)
|
||||
|
||||
return resources
|
||||
|
@ -37,8 +37,8 @@ class AccountController(wsgi.Controller):
|
||||
def show(self, req, tenant_id, id):
|
||||
"""Return a account and instances associated with a single account."""
|
||||
LOG.info(_("req : '%s'\n\n") % req)
|
||||
LOG.info(_("Showing account information for '%s' to '%s'")
|
||||
% (id, tenant_id))
|
||||
LOG.info(_("Showing account information for '%s' to '%s'") %
|
||||
(id, tenant_id))
|
||||
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
account = models.Account.load(context, id)
|
||||
|
@ -31,11 +31,12 @@ class AccountView(object):
|
||||
def data(self):
|
||||
instance_list = [InstanceView(instance).data()
|
||||
for instance in self.account.instances]
|
||||
return {'account': {
|
||||
'id': self.account.id,
|
||||
'instances': instance_list,
|
||||
}
|
||||
}
|
||||
return {
|
||||
'account': {
|
||||
'id': self.account.id,
|
||||
'instances': instance_list,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class InstanceView(object):
|
||||
|
@ -21,8 +21,7 @@ from reddwarf.common import extensions
|
||||
from reddwarf.common import wsgi
|
||||
from reddwarf.extensions.mgmt.instances.service import MgmtInstanceController
|
||||
from reddwarf.extensions.mgmt.host.service import HostController
|
||||
from reddwarf.extensions.mgmt.host.instance.service import (
|
||||
HostInstanceController)
|
||||
from reddwarf.extensions.mgmt.host.instance import service as hostservice
|
||||
from reddwarf.extensions.mgmt.volume.service import StorageController
|
||||
|
||||
|
||||
@ -51,40 +50,41 @@ class Mgmt(extensions.ExtensionsDescriptor):
|
||||
serializer = wsgi.ReddwarfResponseSerializer(
|
||||
body_serializers={'application/xml':
|
||||
wsgi.ReddwarfXMLDictSerializer()})
|
||||
instances = extensions.ResourceExtension('{tenant_id}/mgmt/instances',
|
||||
instances = extensions.ResourceExtension(
|
||||
'{tenant_id}/mgmt/instances',
|
||||
MgmtInstanceController(),
|
||||
deserializer=wsgi.ReddwarfRequestDeserializer(),
|
||||
serializer=serializer,
|
||||
member_actions={'root': 'GET',
|
||||
'diagnostics': 'GET',
|
||||
'hwinfo': 'GET',
|
||||
'action': 'POST'},
|
||||
)
|
||||
'action': 'POST'})
|
||||
resources.append(instances)
|
||||
hosts = extensions.ResourceExtension('{tenant_id}/mgmt/hosts',
|
||||
|
||||
hosts = extensions.ResourceExtension(
|
||||
'{tenant_id}/mgmt/hosts',
|
||||
HostController(),
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer,
|
||||
member_actions={},
|
||||
)
|
||||
member_actions={})
|
||||
resources.append(hosts)
|
||||
|
||||
storage = extensions.ResourceExtension('{tenant_id}/mgmt/storage',
|
||||
StorageController(),
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer,
|
||||
member_actions={},
|
||||
)
|
||||
storage = extensions.ResourceExtension(
|
||||
'{tenant_id}/mgmt/storage',
|
||||
StorageController(),
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer,
|
||||
member_actions={})
|
||||
resources.append(storage)
|
||||
|
||||
host_instances = extensions.ResourceExtension('instances',
|
||||
HostInstanceController(),
|
||||
host_instances = extensions.ResourceExtension(
|
||||
'instances',
|
||||
hostservice.HostInstanceController(),
|
||||
parent={'member_name': 'host',
|
||||
'collection_name': '{tenant_id}/mgmt/hosts'},
|
||||
deserializer=wsgi.RequestDeserializer(),
|
||||
serializer=serializer,
|
||||
collection_actions={'action': 'POST'},
|
||||
)
|
||||
collection_actions={'action': 'POST'})
|
||||
resources.append(host_instances)
|
||||
|
||||
return resources
|
||||
|
@ -35,9 +35,7 @@ class HostInstanceController(wsgi.Controller):
|
||||
raise exception.BadRequest(_("Invalid request body."))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
host = models.DetailedHost.load(context, host_id)
|
||||
_actions = {
|
||||
'update': self._action_update
|
||||
}
|
||||
_actions = {'update': self._action_update}
|
||||
selected_action = None
|
||||
for key in body:
|
||||
if key in _actions:
|
||||
|
@ -75,7 +75,7 @@ class DetailedHost(object):
|
||||
except exception.ReddwarfError as re:
|
||||
LOG.error(re)
|
||||
LOG.error("Compute Instance ID found with no associated RD "
|
||||
"instance: %s" % instance['server_id'])
|
||||
"instance: %s" % instance['server_id'])
|
||||
instance['id'] = None
|
||||
|
||||
def update_all(self, context):
|
||||
|
@ -23,8 +23,8 @@ class HostView(object):
|
||||
|
||||
def data(self):
|
||||
return {
|
||||
'instanceCount': self.host.instance_count,
|
||||
'name': self.host.name
|
||||
'instanceCount': self.host.instance_count,
|
||||
'name': self.host.name
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,8 +35,10 @@ def load_mgmt_instances(context, deleted=None):
|
||||
db_infos = instance_models.DBInstance.find_all(deleted=deleted)
|
||||
else:
|
||||
db_infos = instance_models.DBInstance.find_all()
|
||||
instances = MgmtInstances.load_status_from_existing(context,
|
||||
db_infos, mgmt_servers)
|
||||
instances = MgmtInstances.load_status_from_existing(
|
||||
context,
|
||||
db_infos,
|
||||
mgmt_servers)
|
||||
return instances
|
||||
|
||||
|
||||
|
@ -73,10 +73,14 @@ class MgmtInstanceController(InstanceController):
|
||||
server = models.DetailedMgmtInstance.load(context, id)
|
||||
root_history = mysql_models.RootHistory.load(context=context,
|
||||
instance_id=id)
|
||||
return wsgi.Result(views.MgmtInstanceDetailView(server, req=req,
|
||||
add_addresses=self.add_addresses,
|
||||
add_volumes=self.add_volumes,
|
||||
root_history=root_history).data(), 200)
|
||||
return wsgi.Result(
|
||||
views.MgmtInstanceDetailView(
|
||||
server,
|
||||
req=req,
|
||||
add_addresses=self.add_addresses,
|
||||
add_volumes=self.add_volumes,
|
||||
root_history=root_history).data(),
|
||||
200)
|
||||
|
||||
@admin_context
|
||||
def action(self, req, body, tenant_id, id):
|
||||
@ -90,7 +94,7 @@ class MgmtInstanceController(InstanceController):
|
||||
_actions = {
|
||||
'stop': self._action_stop,
|
||||
'reboot': self._action_reboot
|
||||
}
|
||||
}
|
||||
selected_action = None
|
||||
for key in body:
|
||||
if key in _actions:
|
||||
|
@ -73,7 +73,7 @@ class MgmtInstanceDetailView(MgmtInstanceView):
|
||||
if self.instance.server is not None:
|
||||
server = self.instance.server
|
||||
result['instance']['server'].update(
|
||||
{'addresses': server.addresses})
|
||||
{'addresses': server.addresses})
|
||||
if self.root_history:
|
||||
result['instance']['root_enabled'] = self.root_history.created
|
||||
result['instance']['root_enabled_by'] = self.root_history.user
|
||||
@ -126,12 +126,13 @@ class RootHistoryView(object):
|
||||
self.user = user_id
|
||||
|
||||
def data(self):
|
||||
return {'root_history': {
|
||||
'id': self.instance_id,
|
||||
'enabled': self.enabled,
|
||||
'user': self.user,
|
||||
}
|
||||
}
|
||||
return {
|
||||
'root_history': {
|
||||
'id': self.instance_id,
|
||||
'enabled': self.enabled,
|
||||
'user': self.user,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HwInfoView(object):
|
||||
@ -141,11 +142,12 @@ class HwInfoView(object):
|
||||
self.hwinfo = hwinfo
|
||||
|
||||
def data(self):
|
||||
return {'hwinfo': {
|
||||
'mem_total': self.hwinfo['mem_total'],
|
||||
'num_cpus': self.hwinfo['num_cpus'],
|
||||
}
|
||||
return {
|
||||
'hwinfo': {
|
||||
'mem_total': self.hwinfo['mem_total'],
|
||||
'num_cpus': self.hwinfo['num_cpus'],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DiagnosticsView(object):
|
||||
@ -155,13 +157,14 @@ class DiagnosticsView(object):
|
||||
self.diagnostics = diagnostics
|
||||
|
||||
def data(self):
|
||||
return {'diagnostics': {
|
||||
'version': self.diagnostics['version'],
|
||||
'threads': self.diagnostics['threads'],
|
||||
'fdSize': self.diagnostics['fd_size'],
|
||||
'vmSize': self.diagnostics['vm_size'],
|
||||
'vmPeak': self.diagnostics['vm_peak'],
|
||||
'vmRss': self.diagnostics['vm_rss'],
|
||||
'vmHwm': self.diagnostics['vm_hwm'],
|
||||
}
|
||||
return {
|
||||
'diagnostics': {
|
||||
'version': self.diagnostics['version'],
|
||||
'threads': self.diagnostics['threads'],
|
||||
'fdSize': self.diagnostics['fd_size'],
|
||||
'vmSize': self.diagnostics['vm_size'],
|
||||
'vmPeak': self.diagnostics['vm_peak'],
|
||||
'vmRss': self.diagnostics['vm_rss'],
|
||||
'vmHwm': self.diagnostics['vm_hwm'],
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ class StorageView(object):
|
||||
'provision': {'total': self.storage.prov_total,
|
||||
'available': self.storage.prov_avail,
|
||||
'percent': self.storage.prov_percent},
|
||||
'used': self.storage.used
|
||||
}
|
||||
'used': self.storage.used}
|
||||
|
||||
|
||||
class StoragesView(object):
|
||||
|
@ -51,7 +51,7 @@ class Mysql(extensions.ExtensionsDescriptor):
|
||||
'databases',
|
||||
service.SchemaController(),
|
||||
parent={'member_name': 'instance',
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
deserializer=wsgi.ReddwarfRequestDeserializer(),
|
||||
serializer=serializer)
|
||||
resources.append(resource)
|
||||
@ -59,7 +59,7 @@ class Mysql(extensions.ExtensionsDescriptor):
|
||||
'users',
|
||||
service.UserController(),
|
||||
parent={'member_name': 'instance',
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
# deserializer=extensions.ExtensionsXMLSerializer()
|
||||
deserializer=wsgi.ReddwarfRequestDeserializer(),
|
||||
serializer=serializer)
|
||||
@ -68,7 +68,7 @@ class Mysql(extensions.ExtensionsDescriptor):
|
||||
'root',
|
||||
service.RootController(),
|
||||
parent={'member_name': 'instance',
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
'collection_name': '{tenant_id}/instances'},
|
||||
deserializer=wsgi.ReddwarfRequestDeserializer(),
|
||||
serializer=serializer)
|
||||
|
||||
|
@ -35,9 +35,7 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def persisted_models():
|
||||
return {
|
||||
'root_enabled_history': RootHistory,
|
||||
}
|
||||
return {'root_enabled_history': RootHistory}
|
||||
|
||||
|
||||
def load_and_verify(context, instance_id):
|
||||
@ -45,7 +43,7 @@ def load_and_verify(context, instance_id):
|
||||
instance = base_models.Instance.load(context, instance_id)
|
||||
if not instance.is_sql_running:
|
||||
raise exception.UnprocessableEntity(
|
||||
"Instance %s is not ready." % instance.id)
|
||||
"Instance %s is not ready." % instance.id)
|
||||
else:
|
||||
return instance
|
||||
|
||||
@ -66,10 +64,13 @@ class User(object):
|
||||
client = create_guest_client(context, instance_id)
|
||||
for user in users:
|
||||
user_name = user['_name']
|
||||
existing_users, _nadda = Users.load_with_client(client, limit=1,
|
||||
marker=user_name, include_marker=True)
|
||||
if len(existing_users) > 0 and \
|
||||
str(existing_users[0].name) == str(user_name):
|
||||
existing_users, _nadda = Users.load_with_client(
|
||||
client,
|
||||
limit=1,
|
||||
marker=user_name,
|
||||
include_marker=True)
|
||||
if (len(existing_users) > 0 and
|
||||
str(existing_users[0].name) == str(user_name)):
|
||||
raise exception.UserAlreadyExists(name=user_name)
|
||||
return client.create_user(users)
|
||||
|
||||
@ -158,8 +159,10 @@ class Users(object):
|
||||
|
||||
@classmethod
|
||||
def load_with_client(cls, client, limit, marker, include_marker):
|
||||
user_list, next_marker = client.list_users(limit=limit,
|
||||
marker=marker, include_marker=include_marker)
|
||||
user_list, next_marker = client.list_users(
|
||||
limit=limit,
|
||||
marker=marker,
|
||||
include_marker=include_marker)
|
||||
model_users = []
|
||||
ignore_users = CONFIG.get_list('ignore_users', [])
|
||||
for user in user_list:
|
||||
@ -193,10 +196,13 @@ class Schema(object):
|
||||
client = create_guest_client(context, instance_id)
|
||||
for schema in schemas:
|
||||
schema_name = schema['_name']
|
||||
existing_schema, _nadda = Schemas.load_with_client(client, limit=1,
|
||||
marker=schema_name, include_marker=True)
|
||||
if len(existing_schema) > 0 and \
|
||||
str(existing_schema[0].name) == str(schema_name):
|
||||
existing_schema, _nadda = Schemas.load_with_client(
|
||||
client,
|
||||
limit=1,
|
||||
marker=schema_name,
|
||||
include_marker=True)
|
||||
if (len(existing_schema) > 0 and
|
||||
str(existing_schema[0].name) == str(schema_name)):
|
||||
raise exception.DatabaseAlreadyExists(name=schema_name)
|
||||
return client.create_database(schemas)
|
||||
|
||||
@ -216,8 +222,10 @@ class Schemas(object):
|
||||
|
||||
@classmethod
|
||||
def load_with_client(cls, client, limit, marker, include_marker):
|
||||
schemas, next_marker = client.list_databases(limit=limit,
|
||||
marker=marker, include_marker=include_marker)
|
||||
schemas, next_marker = client.list_databases(
|
||||
limit=limit,
|
||||
marker=marker,
|
||||
include_marker=include_marker)
|
||||
model_schemas = []
|
||||
ignore_dbs = CONFIG.get_list('ignore_dbs', [])
|
||||
for schema in schemas:
|
||||
|
@ -26,12 +26,14 @@ class FlavorView(object):
|
||||
self.req = req
|
||||
|
||||
def data(self):
|
||||
return {"flavor": {
|
||||
'id': int(self.flavor.id),
|
||||
'links': self._build_links(),
|
||||
'name': self.flavor.name,
|
||||
'ram': self.flavor.ram,
|
||||
}}
|
||||
return {
|
||||
"flavor": {
|
||||
'id': int(self.flavor.id),
|
||||
'links': self._build_links(),
|
||||
'name': self.flavor.name,
|
||||
'ram': self.flavor.ram,
|
||||
}
|
||||
}
|
||||
|
||||
def _build_links(self):
|
||||
return create_links("flavors", self.req, self.flavor.id)
|
||||
|
@ -152,7 +152,8 @@ class API(object):
|
||||
"""Make an asynchronous call to prepare the guest
|
||||
as a database container"""
|
||||
LOG.debug(_("Sending the call to prepare the Guest"))
|
||||
self._cast_with_consumer("prepare", databases=databases,
|
||||
self._cast_with_consumer(
|
||||
"prepare", databases=databases,
|
||||
memory_mb=memory_mb, users=users, device_path=device_path,
|
||||
mount_point=mount_point)
|
||||
|
||||
|
@ -142,132 +142,132 @@ class MySQLDatabase(Base):
|
||||
"eucjpms": ["eucjpms_japanese_ci", "eucjpms_bin"]}
|
||||
|
||||
collation = {"big5_chinese_ci": "big5",
|
||||
"big5_bin": "big5",
|
||||
"dec8_swedish_ci": "dec8",
|
||||
"dec8_bin": "dec8",
|
||||
"cp850_general_ci": "cp850",
|
||||
"cp850_bin": "cp850",
|
||||
"hp8_english_ci": "hp8",
|
||||
"hp8_bin": "hp8",
|
||||
"koi8r_general_ci": "koi8r",
|
||||
"koi8r_bin": "koi8r",
|
||||
"latin1_german1_ci": "latin1",
|
||||
"latin1_swedish_ci": "latin1",
|
||||
"latin1_danish_ci": "latin1",
|
||||
"latin1_german2_ci": "latin1",
|
||||
"latin1_bin": "latin1",
|
||||
"latin1_general_ci": "latin1",
|
||||
"latin1_general_cs": "latin1",
|
||||
"latin1_spanish_ci": "latin1",
|
||||
"latin2_czech_cs": "latin2",
|
||||
"latin2_general_ci": "latin2",
|
||||
"latin2_hungarian_ci": "latin2",
|
||||
"latin2_croatian_ci": "latin2",
|
||||
"latin2_bin": "latin2",
|
||||
"swe7_swedish_ci": "swe7",
|
||||
"swe7_bin": "swe7",
|
||||
"ascii_general_ci": "ascii",
|
||||
"ascii_bin": "ascii",
|
||||
"ujis_japanese_ci": "ujis",
|
||||
"ujis_bin": "ujis",
|
||||
"sjis_japanese_ci": "sjis",
|
||||
"sjis_bin": "sjis",
|
||||
"hebrew_general_ci": "hebrew",
|
||||
"hebrew_bin": "hebrew",
|
||||
"tis620_thai_ci": "tis620",
|
||||
"tis620_bin": "tis620",
|
||||
"euckr_korean_ci": "euckr",
|
||||
"euckr_bin": "euckr",
|
||||
"koi8u_general_ci": "koi8u",
|
||||
"koi8u_bin": "koi8u",
|
||||
"gb2312_chinese_ci": "gb2312",
|
||||
"gb2312_bin": "gb2312",
|
||||
"greek_general_ci": "greek",
|
||||
"greek_bin": "greek",
|
||||
"cp1250_general_ci": "cp1250",
|
||||
"cp1250_czech_cs": "cp1250",
|
||||
"cp1250_croatian_ci": "cp1250",
|
||||
"cp1250_bin": "cp1250",
|
||||
"cp1250_polish_ci": "cp1250",
|
||||
"gbk_chinese_ci": "gbk",
|
||||
"gbk_bin": "gbk",
|
||||
"latin5_turkish_ci": "latin5",
|
||||
"latin5_bin": "latin5",
|
||||
"armscii8_general_ci": "armscii8",
|
||||
"armscii8_bin": "armscii8",
|
||||
"utf8_general_ci": "utf8",
|
||||
"utf8_bin": "utf8",
|
||||
"utf8_unicode_ci": "utf8",
|
||||
"utf8_icelandic_ci": "utf8",
|
||||
"utf8_latvian_ci": "utf8",
|
||||
"utf8_romanian_ci": "utf8",
|
||||
"utf8_slovenian_ci": "utf8",
|
||||
"utf8_polish_ci": "utf8",
|
||||
"utf8_estonian_ci": "utf8",
|
||||
"utf8_spanish_ci": "utf8",
|
||||
"utf8_swedish_ci": "utf8",
|
||||
"utf8_turkish_ci": "utf8",
|
||||
"utf8_czech_ci": "utf8",
|
||||
"utf8_danish_ci": "utf8",
|
||||
"utf8_lithuanian_ci": "utf8",
|
||||
"utf8_slovak_ci": "utf8",
|
||||
"utf8_spanish2_ci": "utf8",
|
||||
"utf8_roman_ci": "utf8",
|
||||
"utf8_persian_ci": "utf8",
|
||||
"utf8_esperanto_ci": "utf8",
|
||||
"utf8_hungarian_ci": "utf8",
|
||||
"ucs2_general_ci": "ucs2",
|
||||
"ucs2_bin": "ucs2",
|
||||
"ucs2_unicode_ci": "ucs2",
|
||||
"ucs2_icelandic_ci": "ucs2",
|
||||
"ucs2_latvian_ci": "ucs2",
|
||||
"ucs2_romanian_ci": "ucs2",
|
||||
"ucs2_slovenian_ci": "ucs2",
|
||||
"ucs2_polish_ci": "ucs2",
|
||||
"ucs2_estonian_ci": "ucs2",
|
||||
"ucs2_spanish_ci": "ucs2",
|
||||
"ucs2_swedish_ci": "ucs2",
|
||||
"ucs2_turkish_ci": "ucs2",
|
||||
"ucs2_czech_ci": "ucs2",
|
||||
"ucs2_danish_ci": "ucs2",
|
||||
"ucs2_lithuanian_ci": "ucs2",
|
||||
"ucs2_slovak_ci": "ucs2",
|
||||
"ucs2_spanish2_ci": "ucs2",
|
||||
"ucs2_roman_ci": "ucs2",
|
||||
"ucs2_persian_ci": "ucs2",
|
||||
"ucs2_esperanto_ci": "ucs2",
|
||||
"ucs2_hungarian_ci": "ucs2",
|
||||
"cp866_general_ci": "cp866",
|
||||
"cp866_bin": "cp866",
|
||||
"keybcs2_general_ci": "keybcs2",
|
||||
"keybcs2_bin": "keybcs2",
|
||||
"macce_general_ci": "macce",
|
||||
"macce_bin": "macce",
|
||||
"macroman_general_ci": "macroman",
|
||||
"macroman_bin": "macroman",
|
||||
"cp852_general_ci": "cp852",
|
||||
"cp852_bin": "cp852",
|
||||
"latin7_estonian_cs": "latin7",
|
||||
"latin7_general_ci": "latin7",
|
||||
"latin7_general_cs": "latin7",
|
||||
"latin7_bin": "latin7",
|
||||
"cp1251_bulgarian_ci": "cp1251",
|
||||
"cp1251_ukrainian_ci": "cp1251",
|
||||
"cp1251_bin": "cp1251",
|
||||
"cp1251_general_ci": "cp1251",
|
||||
"cp1251_general_cs": "cp1251",
|
||||
"cp1256_general_ci": "cp1256",
|
||||
"cp1256_bin": "cp1256",
|
||||
"cp1257_lithuanian_ci": "cp1257",
|
||||
"cp1257_bin": "cp1257",
|
||||
"cp1257_general_ci": "cp1257",
|
||||
"binary": "binary",
|
||||
"geostd8_general_ci": "geostd8",
|
||||
"geostd8_bin": "geostd8",
|
||||
"cp932_japanese_ci": "cp932",
|
||||
"cp932_bin": "cp932",
|
||||
"eucjpms_japanese_ci": "eucjpms",
|
||||
"eucjpms_bin": "eucjpms"}
|
||||
"big5_bin": "big5",
|
||||
"dec8_swedish_ci": "dec8",
|
||||
"dec8_bin": "dec8",
|
||||
"cp850_general_ci": "cp850",
|
||||
"cp850_bin": "cp850",
|
||||
"hp8_english_ci": "hp8",
|
||||
"hp8_bin": "hp8",
|
||||
"koi8r_general_ci": "koi8r",
|
||||
"koi8r_bin": "koi8r",
|
||||
"latin1_german1_ci": "latin1",
|
||||
"latin1_swedish_ci": "latin1",
|
||||
"latin1_danish_ci": "latin1",
|
||||
"latin1_german2_ci": "latin1",
|
||||
"latin1_bin": "latin1",
|
||||
"latin1_general_ci": "latin1",
|
||||
"latin1_general_cs": "latin1",
|
||||
"latin1_spanish_ci": "latin1",
|
||||
"latin2_czech_cs": "latin2",
|
||||
"latin2_general_ci": "latin2",
|
||||
"latin2_hungarian_ci": "latin2",
|
||||
"latin2_croatian_ci": "latin2",
|
||||
"latin2_bin": "latin2",
|
||||
"swe7_swedish_ci": "swe7",
|
||||
"swe7_bin": "swe7",
|
||||
"ascii_general_ci": "ascii",
|
||||
"ascii_bin": "ascii",
|
||||
"ujis_japanese_ci": "ujis",
|
||||
"ujis_bin": "ujis",
|
||||
"sjis_japanese_ci": "sjis",
|
||||
"sjis_bin": "sjis",
|
||||
"hebrew_general_ci": "hebrew",
|
||||
"hebrew_bin": "hebrew",
|
||||
"tis620_thai_ci": "tis620",
|
||||
"tis620_bin": "tis620",
|
||||
"euckr_korean_ci": "euckr",
|
||||
"euckr_bin": "euckr",
|
||||
"koi8u_general_ci": "koi8u",
|
||||
"koi8u_bin": "koi8u",
|
||||
"gb2312_chinese_ci": "gb2312",
|
||||
"gb2312_bin": "gb2312",
|
||||
"greek_general_ci": "greek",
|
||||
"greek_bin": "greek",
|
||||
"cp1250_general_ci": "cp1250",
|
||||
"cp1250_czech_cs": "cp1250",
|
||||
"cp1250_croatian_ci": "cp1250",
|
||||
"cp1250_bin": "cp1250",
|
||||
"cp1250_polish_ci": "cp1250",
|
||||
"gbk_chinese_ci": "gbk",
|
||||
"gbk_bin": "gbk",
|
||||
"latin5_turkish_ci": "latin5",
|
||||
"latin5_bin": "latin5",
|
||||
"armscii8_general_ci": "armscii8",
|
||||
"armscii8_bin": "armscii8",
|
||||
"utf8_general_ci": "utf8",
|
||||
"utf8_bin": "utf8",
|
||||
"utf8_unicode_ci": "utf8",
|
||||
"utf8_icelandic_ci": "utf8",
|
||||
"utf8_latvian_ci": "utf8",
|
||||
"utf8_romanian_ci": "utf8",
|
||||
"utf8_slovenian_ci": "utf8",
|
||||
"utf8_polish_ci": "utf8",
|
||||
"utf8_estonian_ci": "utf8",
|
||||
"utf8_spanish_ci": "utf8",
|
||||
"utf8_swedish_ci": "utf8",
|
||||
"utf8_turkish_ci": "utf8",
|
||||
"utf8_czech_ci": "utf8",
|
||||
"utf8_danish_ci": "utf8",
|
||||
"utf8_lithuanian_ci": "utf8",
|
||||
"utf8_slovak_ci": "utf8",
|
||||
"utf8_spanish2_ci": "utf8",
|
||||
"utf8_roman_ci": "utf8",
|
||||
"utf8_persian_ci": "utf8",
|
||||
"utf8_esperanto_ci": "utf8",
|
||||
"utf8_hungarian_ci": "utf8",
|
||||
"ucs2_general_ci": "ucs2",
|
||||
"ucs2_bin": "ucs2",
|
||||
"ucs2_unicode_ci": "ucs2",
|
||||
"ucs2_icelandic_ci": "ucs2",
|
||||
"ucs2_latvian_ci": "ucs2",
|
||||
"ucs2_romanian_ci": "ucs2",
|
||||
"ucs2_slovenian_ci": "ucs2",
|
||||
"ucs2_polish_ci": "ucs2",
|
||||
"ucs2_estonian_ci": "ucs2",
|
||||
"ucs2_spanish_ci": "ucs2",
|
||||
"ucs2_swedish_ci": "ucs2",
|
||||
"ucs2_turkish_ci": "ucs2",
|
||||
"ucs2_czech_ci": "ucs2",
|
||||
"ucs2_danish_ci": "ucs2",
|
||||
"ucs2_lithuanian_ci": "ucs2",
|
||||
"ucs2_slovak_ci": "ucs2",
|
||||
"ucs2_spanish2_ci": "ucs2",
|
||||
"ucs2_roman_ci": "ucs2",
|
||||
"ucs2_persian_ci": "ucs2",
|
||||
"ucs2_esperanto_ci": "ucs2",
|
||||
"ucs2_hungarian_ci": "ucs2",
|
||||
"cp866_general_ci": "cp866",
|
||||
"cp866_bin": "cp866",
|
||||
"keybcs2_general_ci": "keybcs2",
|
||||
"keybcs2_bin": "keybcs2",
|
||||
"macce_general_ci": "macce",
|
||||
"macce_bin": "macce",
|
||||
"macroman_general_ci": "macroman",
|
||||
"macroman_bin": "macroman",
|
||||
"cp852_general_ci": "cp852",
|
||||
"cp852_bin": "cp852",
|
||||
"latin7_estonian_cs": "latin7",
|
||||
"latin7_general_ci": "latin7",
|
||||
"latin7_general_cs": "latin7",
|
||||
"latin7_bin": "latin7",
|
||||
"cp1251_bulgarian_ci": "cp1251",
|
||||
"cp1251_ukrainian_ci": "cp1251",
|
||||
"cp1251_bin": "cp1251",
|
||||
"cp1251_general_ci": "cp1251",
|
||||
"cp1251_general_cs": "cp1251",
|
||||
"cp1256_general_ci": "cp1256",
|
||||
"cp1256_bin": "cp1256",
|
||||
"cp1257_lithuanian_ci": "cp1257",
|
||||
"cp1257_bin": "cp1257",
|
||||
"cp1257_general_ci": "cp1257",
|
||||
"binary": "binary",
|
||||
"geostd8_general_ci": "geostd8",
|
||||
"geostd8_bin": "geostd8",
|
||||
"cp932_japanese_ci": "cp932",
|
||||
"cp932_bin": "cp932",
|
||||
"eucjpms_japanese_ci": "eucjpms",
|
||||
"eucjpms_bin": "eucjpms"}
|
||||
|
||||
def __init__(self):
|
||||
self._name = None
|
||||
@ -286,12 +286,11 @@ class MySQLDatabase(Base):
|
||||
if any([not value,
|
||||
not self._is_valid(value),
|
||||
not self.dbname.match(value),
|
||||
string.find("%r" % value, "\\") != -1,
|
||||
]):
|
||||
string.find("%r" % value, "\\") != -1]):
|
||||
raise ValueError("'%s' is not a valid database name" % value)
|
||||
elif len(value) > 64:
|
||||
raise ValueError("Database name '%s' is too long. Max length = 64"
|
||||
% value)
|
||||
msg = "Database name '%s' is too long. Max length = 64"
|
||||
raise ValueError(msg % value)
|
||||
else:
|
||||
self._name = value
|
||||
|
||||
@ -312,8 +311,8 @@ class MySQLDatabase(Base):
|
||||
pass
|
||||
elif self._character_set:
|
||||
if not value in self.charset[self._character_set]:
|
||||
raise ValueError("'%s' not a valid collation for charset '%s'"
|
||||
% (value, self._character_set))
|
||||
msg = "'%s' not a valid collation for charset '%s'"
|
||||
raise ValueError(msg % (value, self._character_set))
|
||||
self._collate = value
|
||||
else:
|
||||
if not value in self.collation:
|
||||
@ -352,16 +351,16 @@ class MySQLUser(Base):
|
||||
self._databases = []
|
||||
|
||||
def _is_valid(self, value):
|
||||
if (not value or
|
||||
self.not_supported_chars.search(value) or
|
||||
string.find("%r" % value, "\\") != -1):
|
||||
if any([not value,
|
||||
self.not_supported_chars.search(value),
|
||||
string.find("%r" % value, "\\") != -1]):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _is_valid_user_name(self, value):
|
||||
if (self._is_valid(value) and
|
||||
value.lower() not in self._ignore_users):
|
||||
value.lower() not in self._ignore_users):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -374,8 +373,8 @@ class MySQLUser(Base):
|
||||
if not self._is_valid_user_name(value):
|
||||
raise ValueError("'%s' is not a valid user name" % value)
|
||||
elif len(value) > 16:
|
||||
raise ValueError("User name '%s' is too long. Max length = 16"
|
||||
% value)
|
||||
raise ValueError("User name '%s' is too long. Max length = 16" %
|
||||
value)
|
||||
else:
|
||||
self._name = value
|
||||
|
||||
|
@ -78,8 +78,11 @@ def generate_random_password():
|
||||
|
||||
|
||||
def get_auth_password():
|
||||
pwd, err = utils.execute_with_timeout("sudo", "awk",
|
||||
"/password\\t=/{print $3}", "/etc/mysql/my.cnf")
|
||||
pwd, err = utils.execute_with_timeout(
|
||||
"sudo",
|
||||
"awk",
|
||||
"/password\\t=/{print $3}",
|
||||
"/etc/mysql/my.cnf")
|
||||
if err:
|
||||
LOG.err(err)
|
||||
raise RuntimeError("Problem reading my.cnf! : %s" % err)
|
||||
@ -176,7 +179,8 @@ class MySqlAppStatus(object):
|
||||
def _get_actual_db_status(self):
|
||||
global MYSQLD_ARGS
|
||||
try:
|
||||
out, err = utils.execute_with_timeout("/usr/bin/mysqladmin",
|
||||
out, err = utils.execute_with_timeout(
|
||||
"/usr/bin/mysqladmin",
|
||||
"ping", run_as_root=True)
|
||||
LOG.info("Service Status is RUNNING.")
|
||||
return rd_models.ServiceStatuses.RUNNING
|
||||
@ -208,9 +212,9 @@ class MySqlAppStatus(object):
|
||||
True if MySQL app should be installed and attempts to ascertain
|
||||
its status won't result in nonsense.
|
||||
"""
|
||||
return self.status is not None and \
|
||||
self.status != rd_models.ServiceStatuses.BUILDING and \
|
||||
self.status != rd_models.ServiceStatuses.FAILED
|
||||
return all([self.status is not None,
|
||||
self.status != rd_models.ServiceStatuses.BUILDING,
|
||||
self.status != rd_models.ServiceStatuses.FAILED])
|
||||
|
||||
@property
|
||||
def _is_mysql_restarting(self):
|
||||
@ -219,8 +223,8 @@ class MySqlAppStatus(object):
|
||||
@property
|
||||
def is_mysql_running(self):
|
||||
"""True if MySQL is running."""
|
||||
return self.status is not None and \
|
||||
self.status == rd_models.ServiceStatuses.RUNNING
|
||||
return (self.status is not None,
|
||||
self.status == rd_models.ServiceStatuses.RUNNING)
|
||||
|
||||
@staticmethod
|
||||
def _load_status():
|
||||
@ -338,8 +342,8 @@ class MySqlAdmin(object):
|
||||
mydb = models.MySQLDatabase()
|
||||
mydb.deserialize(database)
|
||||
t = text("""
|
||||
GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@:host;"""
|
||||
% (mydb.name, user.name))
|
||||
GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@:host;
|
||||
""" % (mydb.name, user.name))
|
||||
client.execute(t, host=host)
|
||||
|
||||
def delete_database(self, database):
|
||||
@ -420,8 +424,9 @@ class MySqlAdmin(object):
|
||||
if limit:
|
||||
q.limit = limit + 1
|
||||
if marker:
|
||||
q.where.append("schema_name %s '%s'"
|
||||
% (INCLUDE_MARKER_OPERATORS[include_marker], marker))
|
||||
q.where.append("schema_name %s '%s'" %
|
||||
(INCLUDE_MARKER_OPERATORS[include_marker],
|
||||
marker))
|
||||
t = text(str(q))
|
||||
database_names = client.execute(t)
|
||||
next_marker = None
|
||||
@ -454,8 +459,9 @@ class MySqlAdmin(object):
|
||||
q.where = ["host != 'localhost'"]
|
||||
q.order = ['User']
|
||||
if marker:
|
||||
q.where.append("User %s '%s'"
|
||||
% (INCLUDE_MARKER_OPERATORS[include_marker], marker))
|
||||
q.where.append("User %s '%s'" %
|
||||
(INCLUDE_MARKER_OPERATORS[include_marker],
|
||||
marker))
|
||||
if limit:
|
||||
q.limit = limit + 1
|
||||
t = text(str(q))
|
||||
@ -478,8 +484,8 @@ class MySqlAdmin(object):
|
||||
db_result = client.execute(t)
|
||||
for db in db_result:
|
||||
matches = re.match("^'(.+)'@", db['grantee'])
|
||||
if matches is not None and \
|
||||
matches.group(1) == mysql_user.name:
|
||||
if (matches is not None and
|
||||
matches.group(1) == mysql_user.name):
|
||||
mysql_db = models.MySQLDatabase()
|
||||
mysql_db.name = db['table_schema']
|
||||
mysql_user.databases.append(mysql_db.serialize())
|
||||
@ -669,8 +675,8 @@ class MySqlApp(object):
|
||||
LOG.info(_("Stopping mysql..."))
|
||||
utils.execute_with_timeout("sudo", "/etc/init.d/mysql", "stop")
|
||||
if not self.status.wait_for_real_status_to_change_to(
|
||||
rd_models.ServiceStatuses.SHUTDOWN,
|
||||
self.state_change_wait_time, update_db):
|
||||
rd_models.ServiceStatuses.SHUTDOWN,
|
||||
self.state_change_wait_time, update_db):
|
||||
LOG.error(_("Could not stop MySQL!"))
|
||||
self.status.end_install_or_restart()
|
||||
raise RuntimeError("Could not stop MySQL!")
|
||||
@ -703,7 +709,8 @@ class MySqlApp(object):
|
||||
|
||||
def _replace_mycnf_with_template(self, template_path, original_path):
|
||||
if os.path.isfile(template_path):
|
||||
utils.execute_with_timeout("sudo", "mv", original_path,
|
||||
utils.execute_with_timeout(
|
||||
"sudo", "mv", original_path,
|
||||
"%(name)s.%(date)s" % {'name': original_path,
|
||||
'date': date.today().isoformat()})
|
||||
utils.execute_with_timeout("sudo", "cp", template_path,
|
||||
@ -799,8 +806,8 @@ class MySqlApp(object):
|
||||
raise RuntimeError("Can't start MySQL!")
|
||||
|
||||
if not self.status.wait_for_real_status_to_change_to(
|
||||
rd_models.ServiceStatuses.RUNNING,
|
||||
self.state_change_wait_time, update_db):
|
||||
rd_models.ServiceStatuses.RUNNING,
|
||||
self.state_change_wait_time, update_db):
|
||||
LOG.error(_("Start up of MySQL failed!"))
|
||||
self.status.end_install_or_restart()
|
||||
raise RuntimeError("Could not start MySQL!")
|
||||
|
@ -49,7 +49,7 @@ class GuestManager(service.Manager):
|
||||
service_impl = GUEST_SERVICES[service_type]
|
||||
except KeyError as e:
|
||||
LOG.error(_("Could not create guest, no impl for key - %s") %
|
||||
service_type)
|
||||
service_type)
|
||||
raise e
|
||||
LOG.info("Create guest driver %s" % service_impl)
|
||||
self.create_guest_driver(service_impl)
|
||||
|
@ -29,9 +29,7 @@ AGENT_HEARTBEAT = int(config.Config.get('agent_heartbeat_time', '10'))
|
||||
|
||||
|
||||
def persisted_models():
|
||||
return {
|
||||
'agent_heartbeats': AgentHeartBeat,
|
||||
}
|
||||
return {'agent_heartbeats': AgentHeartBeat}
|
||||
|
||||
|
||||
class AgentHeartBeat(dbmodels.DatabaseModelBase):
|
||||
@ -61,5 +59,5 @@ class AgentHeartBeat(dbmodels.DatabaseModelBase):
|
||||
|
||||
@staticmethod
|
||||
def is_active(agent):
|
||||
return (datetime.now() - agent.updated_at) < \
|
||||
timedelta(seconds=AGENT_HEARTBEAT)
|
||||
return (datetime.now() - agent.updated_at <
|
||||
timedelta(seconds=AGENT_HEARTBEAT))
|
||||
|
@ -91,8 +91,8 @@ class PkgAgent(object):
|
||||
i = child.expect(['.*password*',
|
||||
'E: Unable to locate package %s' % package_name,
|
||||
"Couldn't find package % s" % package_name,
|
||||
"dpkg was interrupted, you must manually run "
|
||||
"'sudo dpkg --configure -a'",
|
||||
("dpkg was interrupted, you must manually run "
|
||||
"'sudo dpkg --configure -a'"),
|
||||
"Unable to lock the administration directory",
|
||||
"Setting up %s*" % package_name,
|
||||
"is already the newest version"],
|
||||
@ -131,10 +131,10 @@ class PkgAgent(object):
|
||||
i = child.expect(['.*password*',
|
||||
'E: Unable to locate package %s' % package_name,
|
||||
'Package is in a very bad inconsistent state',
|
||||
"Sub-process /usr/bin/dpkg returned an "
|
||||
"error code",
|
||||
"dpkg was interrupted, you must manually run "
|
||||
"'sudo dpkg --configure -a'",
|
||||
("Sub-process /usr/bin/dpkg returned an error "
|
||||
"code"),
|
||||
("dpkg was interrupted, you must manually run "
|
||||
"'sudo dpkg --configure -a'"),
|
||||
"Unable to lock the administration directory",
|
||||
#'The following packages will be REMOVED',
|
||||
"Removing %s*" % package_name],
|
||||
|
@ -75,7 +75,7 @@ class Query(object):
|
||||
self._order,
|
||||
self._group_by,
|
||||
self._limit,
|
||||
]
|
||||
]
|
||||
return '\n'.join(query)
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -107,8 +107,8 @@ class VolumeDevice(object):
|
||||
utils.execute("sudo", "resize2fs", self.device_path)
|
||||
except ProcessExecutionError as err:
|
||||
LOG.error(err)
|
||||
raise GuestError("Error resizing the filesystem: %s"
|
||||
% self.device_path)
|
||||
raise GuestError("Error resizing the filesystem: %s" %
|
||||
self.device_path)
|
||||
|
||||
def _tmp_mount(self, mount_point):
|
||||
"""Mounts, but doesn't save to fstab."""
|
||||
@ -137,14 +137,16 @@ class VolumeMountPoint(object):
|
||||
"volume_type:%s, mount options:%s" %
|
||||
(self.device_path, self.mount_point, self.volume_fstype,
|
||||
self.mount_options))
|
||||
cmd = "sudo mount -t %s -o %s %s %s" % (self.volume_fstype,
|
||||
self.mount_options, self.device_path, self.mount_point)
|
||||
cmd = ("sudo mount -t %s -o %s %s %s" %
|
||||
(self.volume_fstype, self.mount_options, self.device_path,
|
||||
self.mount_point))
|
||||
child = pexpect.spawn(cmd)
|
||||
child.expect(pexpect.EOF)
|
||||
|
||||
def write_to_fstab(self):
|
||||
fstab_line = "%s\t%s\t%s\t%s\t0\t0" % (self.device_path,
|
||||
self.mount_point, self.volume_fstype, self.mount_options)
|
||||
fstab_line = ("%s\t%s\t%s\t%s\t0\t0" %
|
||||
(self.device_path, self.mount_point, self.volume_fstype,
|
||||
self.mount_options))
|
||||
LOG.debug("Writing new line to fstab:%s" % fstab_line)
|
||||
utils.execute("sudo", "cp", "/etc/fstab", "/etc/fstab.orig")
|
||||
utils.execute("sudo", "cp", "/etc/fstab", "/tmp/newfstab")
|
||||
|
@ -180,8 +180,9 @@ class SimpleInstance(object):
|
||||
if self.db_info.server_status in ["ACTIVE", "SHUTDOWN"]:
|
||||
return InstanceStatus.SHUTDOWN
|
||||
else:
|
||||
LOG.error(_("While shutting down instance (%s): server had "
|
||||
" status (%s).") % (self.id, self.db_info.server_status))
|
||||
msg = _("While shutting down instance (%s): server had "
|
||||
"status (%s).")
|
||||
LOG.error(msg % (self.id, self.db_info.server_status))
|
||||
return InstanceStatus.ERROR
|
||||
|
||||
### Check against the service status.
|
||||
@ -293,8 +294,8 @@ def load_instance_with_guest(cls, context, id):
|
||||
LOG.warn(mnfe)
|
||||
return instance
|
||||
|
||||
if instance.status not in AGENT_INVALID_STATUSES and \
|
||||
agent_models.AgentHeartBeat.is_active(agent):
|
||||
if (instance.status not in AGENT_INVALID_STATUSES and
|
||||
agent_models.AgentHeartBeat.is_active(agent)):
|
||||
guest = create_guest_client(context, id)
|
||||
try:
|
||||
instance.volume_used = guest.get_volume_info()['used']
|
||||
@ -319,8 +320,8 @@ class BaseInstance(SimpleInstance):
|
||||
def delete(self):
|
||||
if (self.db_info.server_status in ["BUILD"] and
|
||||
not self.db_info.task_status.is_error):
|
||||
raise exception.UnprocessableEntity("Instance %s is not ready."
|
||||
% self.id)
|
||||
raise exception.UnprocessableEntity("Instance %s is not ready." %
|
||||
self.id)
|
||||
LOG.debug(_(" ... deleting compute id = %s") %
|
||||
self.db_info.compute_instance_id)
|
||||
LOG.debug(_(" ... setting status to DELETING."))
|
||||
@ -402,13 +403,15 @@ class Instance(BuiltInstance):
|
||||
except nova_exceptions.NotFound:
|
||||
raise exception.FlavorNotFound(uuid=flavor_id)
|
||||
|
||||
db_info = DBInstance.create(name=name,
|
||||
flavor_id=flavor_id, tenant_id=context.tenant,
|
||||
volume_size=volume_size, task_status=InstanceTasks.BUILDING)
|
||||
db_info = DBInstance.create(name=name, flavor_id=flavor_id,
|
||||
tenant_id=context.tenant,
|
||||
volume_size=volume_size,
|
||||
task_status=InstanceTasks.BUILDING)
|
||||
LOG.debug(_("Tenant %s created new Reddwarf instance %s...")
|
||||
% (context.tenant, db_info.id))
|
||||
|
||||
service_status = InstanceServiceStatus.create(instance_id=db_info.id,
|
||||
service_status = InstanceServiceStatus.create(
|
||||
instance_id=db_info.id,
|
||||
status=ServiceStatuses.NEW)
|
||||
|
||||
dns_support = config.Config.get("reddwarf_dns_support", 'False')
|
||||
@ -419,7 +422,9 @@ class Instance(BuiltInstance):
|
||||
db_info.save()
|
||||
|
||||
task_api.API(context).create_instance(db_info.id, name, flavor_id,
|
||||
flavor.ram, image_id, databases, users, service_type, volume_size)
|
||||
flavor.ram, image_id, databases,
|
||||
users, service_type,
|
||||
volume_size)
|
||||
|
||||
return SimpleInstance(context, db_info, service_status)
|
||||
|
||||
@ -444,7 +449,8 @@ class Instance(BuiltInstance):
|
||||
self.update_db(task_status=InstanceTasks.RESIZING)
|
||||
LOG.debug("Instance %s set to RESIZING." % self.id)
|
||||
task_api.API(self.context).resize_flavor(self.id, new_flavor_id,
|
||||
old_flavor_size, new_flavor_size)
|
||||
old_flavor_size,
|
||||
new_flavor_size)
|
||||
|
||||
def resize_volume(self, new_size):
|
||||
self._validate_can_perform_action()
|
||||
@ -453,8 +459,9 @@ class Instance(BuiltInstance):
|
||||
raise exception.BadRequest("Instance %s has no volume." % self.id)
|
||||
old_size = self.volume_size
|
||||
if int(new_size) <= old_size:
|
||||
raise exception.BadRequest("The new volume 'size' must be larger "
|
||||
"than the current volume size of '%s'" % old_size)
|
||||
msg = ("The new volume 'size' must be larger than the current "
|
||||
"volume size of '%s'")
|
||||
raise exception.BadRequest(msg % old_size)
|
||||
# Set the task to Resizing before sending off to the taskmanager
|
||||
self.update_db(task_status=InstanceTasks.RESIZING)
|
||||
task_api.API(self.context).resize_volume(new_size, self.id)
|
||||
@ -481,12 +488,12 @@ class Instance(BuiltInstance):
|
||||
"""
|
||||
Raises exception if an instance action cannot currently be performed.
|
||||
"""
|
||||
if self.db_info.server_status != "ACTIVE" or \
|
||||
self.db_info.task_status != InstanceTasks.NONE or \
|
||||
not self.service_status.status.action_is_allowed:
|
||||
msg = "Instance is not currently available for an action to be " \
|
||||
"performed (status was %s)." % self.status
|
||||
LOG.error(msg)
|
||||
if any([self.db_info.server_status != "ACTIVE",
|
||||
self.db_info.task_status != InstanceTasks.NONE,
|
||||
not self.service_status.status.action_is_allowed]):
|
||||
msg = ("Instance is not currently available for an action to be "
|
||||
"performed (status was %s).")
|
||||
LOG.error(msg % self.status)
|
||||
raise exception.UnprocessableEntity(msg)
|
||||
|
||||
|
||||
@ -504,8 +511,8 @@ def create_server_list_matcher(server_list):
|
||||
instance_id=instance_id, server_id=server_id)
|
||||
else:
|
||||
# Should never happen, but never say never.
|
||||
LOG.error(_("Server %s for instance %s was found twice!")
|
||||
% (server_id, instance_id))
|
||||
LOG.error(_("Server %s for instance %s was found twice!") %
|
||||
(server_id, instance_id))
|
||||
raise exception.ReddwarfError(uuid=instance_id)
|
||||
return find_server
|
||||
|
||||
@ -563,14 +570,14 @@ class Instances(object):
|
||||
#volumes = find_volumes(server.id)
|
||||
status = InstanceServiceStatus.find_by(instance_id=db.id)
|
||||
LOG.info(_("Server api_status(%s)") %
|
||||
(status.status.api_status))
|
||||
(status.status.api_status))
|
||||
if not status.status: # This should never happen.
|
||||
LOG.error(_("Server status could not be read for "
|
||||
"instance id(%s)") % (db.id))
|
||||
continue
|
||||
except exception.ModelNotFoundError:
|
||||
LOG.error(_("Server status could not be read for "
|
||||
"instance id(%s)") % (db.id))
|
||||
"instance id(%s)") % (db.id))
|
||||
continue
|
||||
ret.append(load_instance(context, db, status))
|
||||
return ret
|
||||
@ -645,7 +652,7 @@ def persisted_models():
|
||||
'instance': DBInstance,
|
||||
'service_image': ServiceImage,
|
||||
'service_statuses': InstanceServiceStatus,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ServiceStatus(object):
|
||||
@ -664,9 +671,13 @@ class ServiceStatus(object):
|
||||
|
||||
@property
|
||||
def action_is_allowed(self):
|
||||
return self._code in [ServiceStatuses.RUNNING._code,
|
||||
ServiceStatuses.SHUTDOWN._code, ServiceStatuses.CRASHED._code,
|
||||
ServiceStatuses.BLOCKED._code]
|
||||
allowed_statuses = [
|
||||
ServiceStatuses.RUNNING._code,
|
||||
ServiceStatuses.SHUTDOWN._code,
|
||||
ServiceStatuses.CRASHED._code,
|
||||
ServiceStatuses.BLOCKED._code,
|
||||
]
|
||||
return self._code in allowed_statuses
|
||||
|
||||
@property
|
||||
def api_status(self):
|
||||
|
@ -65,7 +65,7 @@ class InstanceController(wsgi.Controller):
|
||||
'restart': self._action_restart,
|
||||
'resize': self._action_resize,
|
||||
'reset_password': self._action_reset_password
|
||||
}
|
||||
}
|
||||
selected_action = None
|
||||
for key in body:
|
||||
if key in _actions:
|
||||
@ -216,8 +216,9 @@ class InstanceController(wsgi.Controller):
|
||||
image_id, databases, users,
|
||||
service_type, volume_size)
|
||||
|
||||
return wsgi.Result(views.InstanceDetailView(instance, req=req,
|
||||
add_volumes=self.add_volumes).data(), 200)
|
||||
view = views.InstanceDetailView(instance, req=req,
|
||||
add_volumes=self.add_volumes)
|
||||
return wsgi.Result(view.data(), 200)
|
||||
|
||||
@staticmethod
|
||||
def _validate_body_not_empty(body):
|
||||
@ -267,11 +268,9 @@ class InstanceController(wsgi.Controller):
|
||||
body['instance']
|
||||
body['instance']['flavorRef']
|
||||
vol_enabled = utils.bool_from_string(
|
||||
config.Config.get('reddwarf_volume_support',
|
||||
'True'))
|
||||
config.Config.get('reddwarf_volume_support', 'True'))
|
||||
must_have_vol = utils.bool_from_string(
|
||||
config.Config.get('reddwarf_must_use_volume',
|
||||
'False'))
|
||||
config.Config.get('reddwarf_must_use_volume', 'False'))
|
||||
if vol_enabled:
|
||||
if body['instance'].get('volume', None):
|
||||
if body['instance']['volume'].get('size', None):
|
||||
@ -285,4 +284,4 @@ class InstanceController(wsgi.Controller):
|
||||
except KeyError as e:
|
||||
LOG.error(_("Create Instance Required field(s) - %s") % e)
|
||||
raise exception.ReddwarfError("Required element/key - %s "
|
||||
"was not specified" % e)
|
||||
"was not specified" % e)
|
||||
|
@ -67,12 +67,14 @@ class InstanceTasks(object):
|
||||
RESIZING = InstanceTask(0x04, 'RESIZING', 'Resizing the instance.')
|
||||
BUILDING = InstanceTask(0x05, 'BUILDING', 'The instance is building.')
|
||||
|
||||
BUILDING_ERROR_DNS = InstanceTask(0x50, 'BUILDING',
|
||||
'Build error: DNS.', is_error=True)
|
||||
BUILDING_ERROR_DNS = InstanceTask(0x50, 'BUILDING', 'Build error: DNS.',
|
||||
is_error=True)
|
||||
BUILDING_ERROR_SERVER = InstanceTask(0x51, 'BUILDING',
|
||||
'Build error: Server.', is_error=True)
|
||||
'Build error: Server.',
|
||||
is_error=True)
|
||||
BUILDING_ERROR_VOLUME = InstanceTask(0x52, 'BUILDING',
|
||||
'Build error: Volume.', is_error=True)
|
||||
'Build error: Volume.',
|
||||
is_error=True)
|
||||
|
||||
|
||||
# Dissuade further additions at run-time.
|
||||
|
@ -25,13 +25,13 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_ip_address(addresses):
|
||||
if addresses is not None and \
|
||||
addresses.get('private') is not None and \
|
||||
len(addresses['private']) > 0:
|
||||
if all([addresses is not None,
|
||||
addresses.get('private') is not None,
|
||||
len(addresses['private']) > 0]):
|
||||
return [addr.get('addr') for addr in addresses['private']]
|
||||
if addresses is not None and\
|
||||
addresses.get('usernet') is not None and\
|
||||
len(addresses['usernet']) > 0:
|
||||
if all([addresses is not None,
|
||||
addresses.get('usernet') is not None,
|
||||
len(addresses['usernet']) > 0]):
|
||||
return [addr.get('addr') for addr in addresses['usernet']]
|
||||
|
||||
|
||||
@ -100,8 +100,8 @@ class InstanceDetailView(InstanceView):
|
||||
if ip is not None and len(ip) > 0:
|
||||
result['instance']['ip'] = ip
|
||||
if self.add_volumes:
|
||||
if isinstance(self.instance, models.DetailInstance) and \
|
||||
self.instance.volume_used:
|
||||
if (isinstance(self.instance, models.DetailInstance) and
|
||||
self.instance.volume_used):
|
||||
used = self._to_gb(self.instance.volume_used)
|
||||
result['instance']['volume']['used'] = used
|
||||
return result
|
||||
|
@ -99,15 +99,15 @@ def add_log_options(parser):
|
||||
"the Python logging module documentation for "
|
||||
"details on logging configuration files.")
|
||||
group.add_option('--log-date-format', metavar="FORMAT",
|
||||
default=DEFAULT_LOG_DATE_FORMAT,
|
||||
help="Format string for %(asctime)s in log records. "
|
||||
"Default: %default")
|
||||
default=DEFAULT_LOG_DATE_FORMAT,
|
||||
help="Format string for %(asctime)s in log records. "
|
||||
"Default: %default")
|
||||
group.add_option('--log-file', default=None, metavar="PATH",
|
||||
help="(Optional) Name of log file to output to. "
|
||||
"If not set, logging will go to stdout.")
|
||||
help="(Optional) Name of log file to output to. "
|
||||
"If not set, logging will go to stdout.")
|
||||
group.add_option("--log-dir", default=None,
|
||||
help="(Optional) The directory to keep log files in "
|
||||
"(will be prepended to --logfile)")
|
||||
help="(Optional) The directory to keep log files in "
|
||||
"(will be prepended to --logfile)")
|
||||
group.add_option('--use-syslog', default=False, dest="use_syslog",
|
||||
action="store_true",
|
||||
help="Use syslog for logging.")
|
||||
@ -249,7 +249,7 @@ def load_paste_config(app_name, options, args, config_dir=None):
|
||||
conf_file = find_config_file(app_name, options, args, config_dir)
|
||||
if not conf_file:
|
||||
raise RuntimeError("Unable to locate any configuration file. "
|
||||
"Cannot load application %s" % app_name)
|
||||
"Cannot load application %s" % app_name)
|
||||
try:
|
||||
conf = deploy.appconfig("config:%s" % conf_file, name=app_name)
|
||||
return conf_file, conf
|
||||
|
@ -220,15 +220,15 @@ class ExtensionMiddleware(wsgi.Middleware):
|
||||
if not action.collection in action_resources.keys():
|
||||
resource = ActionExtensionResource(application)
|
||||
mapper.connect("/%s/:(id)/action.:(format)" %
|
||||
action.collection,
|
||||
action='action',
|
||||
controller=resource,
|
||||
conditions=dict(method=['POST']))
|
||||
action.collection,
|
||||
action='action',
|
||||
controller=resource,
|
||||
conditions=dict(method=['POST']))
|
||||
mapper.connect("/%s/:(id)/action" %
|
||||
action.collection,
|
||||
action='action',
|
||||
controller=resource,
|
||||
conditions=dict(method=['POST']))
|
||||
action.collection,
|
||||
action='action',
|
||||
controller=resource,
|
||||
conditions=dict(method=['POST']))
|
||||
action_resources[action.collection] = resource
|
||||
|
||||
return action_resources
|
||||
@ -240,21 +240,21 @@ class ExtensionMiddleware(wsgi.Middleware):
|
||||
if not req_ext.key in request_ext_resources.keys():
|
||||
resource = RequestExtensionResource(application)
|
||||
mapper.connect(req_ext.url_route + '.:(format)',
|
||||
action='process',
|
||||
controller=resource,
|
||||
conditions=req_ext.conditions)
|
||||
action='process',
|
||||
controller=resource,
|
||||
conditions=req_ext.conditions)
|
||||
|
||||
mapper.connect(req_ext.url_route,
|
||||
action='process',
|
||||
controller=resource,
|
||||
conditions=req_ext.conditions)
|
||||
action='process',
|
||||
controller=resource,
|
||||
conditions=req_ext.conditions)
|
||||
request_ext_resources[req_ext.key] = resource
|
||||
|
||||
return request_ext_resources
|
||||
|
||||
def __init__(self, application, config, ext_mgr=None):
|
||||
ext_mgr = ext_mgr or ExtensionManager(
|
||||
config['api_extensions_path'])
|
||||
ext_mgr = (ext_mgr or
|
||||
ExtensionManager(config['api_extensions_path']))
|
||||
mapper = routes.Mapper()
|
||||
|
||||
# extended resources
|
||||
@ -275,7 +275,7 @@ class ExtensionMiddleware(wsgi.Middleware):
|
||||
|
||||
# extended actions
|
||||
action_resources = self._action_ext_resources(application, ext_mgr,
|
||||
mapper)
|
||||
mapper)
|
||||
for action in ext_mgr.get_actions():
|
||||
LOG.debug(_('Extended action: %s'), action.action_name)
|
||||
resource = action_resources[action.collection]
|
||||
|
@ -121,14 +121,14 @@ def execute(*cmd, **kwargs):
|
||||
if _returncode:
|
||||
LOG.debug(_('Result was %s') % _returncode)
|
||||
if (isinstance(check_exit_code, int) and
|
||||
not isinstance(check_exit_code, bool) and
|
||||
_returncode != check_exit_code):
|
||||
not isinstance(check_exit_code, bool) and
|
||||
_returncode != check_exit_code):
|
||||
(stdout, stderr) = result
|
||||
raise exception.ProcessExecutionError(
|
||||
exit_code=_returncode,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
cmd=' '.join(cmd))
|
||||
exit_code=_returncode,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
cmd=' '.join(cmd))
|
||||
return result
|
||||
except exception.ProcessExecutionError:
|
||||
if not attempts:
|
||||
|
@ -57,7 +57,7 @@ class API(ManagerAPI):
|
||||
|
||||
def resize_volume(self, new_size, instance_id):
|
||||
LOG.debug("Making async call to resize volume for instance: %s"
|
||||
% instance_id)
|
||||
% instance_id)
|
||||
self._cast("resize_volume", new_size=new_size, instance_id=instance_id)
|
||||
|
||||
def resize_flavor(self, instance_id, new_flavor_id, old_memory_size,
|
||||
|
@ -55,13 +55,17 @@ class FreshInstanceTasks(FreshInstance):
|
||||
def create_instance(self, flavor_id, flavor_ram, image_id,
|
||||
databases, users, service_type, volume_size):
|
||||
if use_nova_server_volume:
|
||||
server, volume_info = self._create_server_volume(flavor_id,
|
||||
image_id, service_type,
|
||||
volume_size)
|
||||
server, volume_info = self._create_server_volume(
|
||||
flavor_id,
|
||||
image_id,
|
||||
service_type,
|
||||
volume_size)
|
||||
else:
|
||||
server, volume_info = self._create_server_volume_individually(
|
||||
flavor_id, image_id,
|
||||
service_type, volume_size)
|
||||
flavor_id,
|
||||
image_id,
|
||||
service_type,
|
||||
volume_size)
|
||||
try:
|
||||
self._create_dns_entry()
|
||||
except Exception as e:
|
||||
@ -153,20 +157,22 @@ class FreshInstanceTasks(FreshInstance):
|
||||
|
||||
volume_support = config.Config.get("reddwarf_volume_support", 'False')
|
||||
LOG.debug(_("reddwarf volume support = %s") % volume_support)
|
||||
if volume_size is None or \
|
||||
utils.bool_from_string(volume_support) is False:
|
||||
volume_info = {'block_device': None,
|
||||
'device_path': None,
|
||||
'mount_point': None,
|
||||
'volumes': None}
|
||||
if (volume_size is None or
|
||||
utils.bool_from_string(volume_support) is False):
|
||||
volume_info = {
|
||||
'block_device': None,
|
||||
'device_path': None,
|
||||
'mount_point': None,
|
||||
'volumes': None,
|
||||
}
|
||||
return volume_info
|
||||
|
||||
volume_client = create_nova_volume_client(self.context)
|
||||
volume_desc = ("mysql volume for %s" % self.id)
|
||||
volume_ref = volume_client.volumes.create(
|
||||
volume_size,
|
||||
display_name="mysql-%s" % self.id,
|
||||
display_description=volume_desc)
|
||||
volume_size,
|
||||
display_name="mysql-%s" % self.id,
|
||||
display_description=volume_desc)
|
||||
|
||||
# Record the volume ID in case something goes wrong.
|
||||
self.update_db(volume_id=volume_ref.id)
|
||||
@ -209,8 +215,10 @@ class FreshInstanceTasks(FreshInstance):
|
||||
files = {"/etc/guest_info": "guest_id=%s\nservice_type=%s\n" %
|
||||
(self.id, service_type)}
|
||||
name = self.hostname or self.name
|
||||
bdmap = block_device_mapping
|
||||
server = nova_client.servers.create(name, image_id, flavor_id,
|
||||
files=files, block_device_mapping=block_device_mapping)
|
||||
files=files,
|
||||
block_device_mapping=bdmap)
|
||||
LOG.debug(_("Created new compute instance %s.") % server.id)
|
||||
return server
|
||||
|
||||
@ -219,8 +227,8 @@ class FreshInstanceTasks(FreshInstance):
|
||||
LOG.info("Entering guest_prepare.")
|
||||
# Now wait for the response from the create to do additional work
|
||||
self.guest.prepare(flavor_ram, databases, users,
|
||||
device_path=volume_info['device_path'],
|
||||
mount_point=volume_info['mount_point'])
|
||||
device_path=volume_info['device_path'],
|
||||
mount_point=volume_info['mount_point'])
|
||||
|
||||
def _create_dns_entry(self):
|
||||
LOG.debug("%s: Creating dns entry for instance: %s"
|
||||
@ -240,14 +248,14 @@ class FreshInstanceTasks(FreshInstance):
|
||||
LOG.info("Polling for ip addresses: $%s " % server.addresses)
|
||||
if server.addresses != {}:
|
||||
return True
|
||||
elif server.addresses == {} and\
|
||||
server.status != InstanceStatus.ERROR:
|
||||
elif (server.addresses == {} and
|
||||
server.status != InstanceStatus.ERROR):
|
||||
return False
|
||||
elif server.addresses == {} and\
|
||||
server.status == InstanceStatus.ERROR:
|
||||
LOG.error(_("Instance IP not available, instance (%s): "
|
||||
"server had status (%s).")
|
||||
% (self.id, server.status))
|
||||
elif (server.addresses == {} and
|
||||
server.status == InstanceStatus.ERROR):
|
||||
msg = _("Instance IP not available, instance (%s): "
|
||||
"server had status (%s).")
|
||||
LOG.error(msg % (self.id, server.status))
|
||||
raise ReddwarfError(status=server.status)
|
||||
poll_until(get_server, ip_is_available,
|
||||
sleep_time=1, time_out=60 * 2)
|
||||
@ -310,10 +318,10 @@ class BuiltInstanceTasks(BuiltInstance):
|
||||
self.volume_client.volumes.resize(self.volume_id, int(new_size))
|
||||
try:
|
||||
utils.poll_until(
|
||||
lambda: self.volume_client.volumes.get(self.volume_id),
|
||||
lambda volume: volume.status == 'in-use',
|
||||
sleep_time=2,
|
||||
time_out=int(config.Config.get('volume_time_out')))
|
||||
lambda: self.volume_client.volumes.get(self.volume_id),
|
||||
lambda volume: volume.status == 'in-use',
|
||||
sleep_time=2,
|
||||
time_out=int(config.Config.get('volume_time_out')))
|
||||
volume = self.volume_client.volumes.get(self.volume_id)
|
||||
self.update_db(volume_size=volume.size)
|
||||
self.nova_client.volumes.rescan_server_volume(self.server,
|
||||
@ -348,10 +356,10 @@ class BuiltInstanceTasks(BuiltInstance):
|
||||
|
||||
# Do initial check and confirm the status is appropriate.
|
||||
self._refresh_compute_server_info()
|
||||
if self.server.status != "RESIZE" and\
|
||||
self.server.status != "VERIFY_RESIZE":
|
||||
raise ReddwarfError("Unexpected status after " \
|
||||
"call to resize! : %s" % resize_status_msg())
|
||||
if (self.server.status != "RESIZE" and
|
||||
self.server.status != "VERIFY_RESIZE"):
|
||||
msg = "Unexpected status after call to resize! : %s"
|
||||
raise ReddwarfError(msg % resize_status_msg())
|
||||
|
||||
# Wait for the flavor to change.
|
||||
def update_server_info():
|
||||
@ -365,10 +373,11 @@ class BuiltInstanceTasks(BuiltInstance):
|
||||
|
||||
# Do check to make sure the status and flavor id are correct.
|
||||
if (str(self.server.flavor['id']) != str(new_flavor_id) or
|
||||
self.server.status != "VERIFY_RESIZE"):
|
||||
raise ReddwarfError("Assertion failed! flavor_id=%s "
|
||||
"and not %s"
|
||||
% (str(self.server.flavor['id']), str(new_flavor_id)))
|
||||
self.server.status != "VERIFY_RESIZE"):
|
||||
msg = "Assertion failed! flavor_id=%s and not %s"
|
||||
actual_flavor = self.server.flavor['id']
|
||||
expected_flavor = new_flavor_id
|
||||
raise ReddwarfError(msg % (actual_flavor, expected_flavor))
|
||||
|
||||
# Confirm the resize with Nova.
|
||||
LOG.debug("Instance %s calling Compute confirm resize..."
|
||||
|
@ -56,8 +56,10 @@ class BaseTest(unittest.TestCase):
|
||||
self.maxDiff = None
|
||||
|
||||
self.mock = mox.Mox()
|
||||
conf, reddwarf_app = config.Config.load_paste_app('reddwarfapp',
|
||||
{"config_file": test_config_file()}, None)
|
||||
conf, reddwarf_app = config.Config.load_paste_app(
|
||||
'reddwarfapp',
|
||||
{"config_file": test_config_file()},
|
||||
None)
|
||||
db_api.configure_db(conf)
|
||||
db_api.clean_db()
|
||||
super(BaseTest, self).setUp()
|
||||
@ -73,19 +75,18 @@ class BaseTest(unittest.TestCase):
|
||||
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
self.fail("Expected {0} to raise {1}".format(func,
|
||||
repr(exception)))
|
||||
self.fail("Expected %r to raise %r" % (func, exception))
|
||||
except exception as error:
|
||||
self.assertIn(message, str(error))
|
||||
|
||||
def assertIn(self, expected, actual):
|
||||
"""This is similar to assertIn in python 2.7"""
|
||||
self.assertTrue(expected in actual,
|
||||
"{0} does not contain {1}".format(repr(actual), repr(expected)))
|
||||
"%r does not contain %r" % (actual, expected))
|
||||
|
||||
def assertNotIn(self, expected, actual):
|
||||
self.assertFalse(expected in actual,
|
||||
"{0} does contains {1}".format(repr(actual), repr(expected)))
|
||||
"%r does not contain %r" % (actual, expected))
|
||||
|
||||
def assertIsNone(self, actual):
|
||||
"""This is similar to assertIsNone in python 2.7"""
|
||||
@ -99,14 +100,16 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(sorted(expected), sorted(actual))
|
||||
|
||||
def assertModelsEqual(self, expected, actual):
|
||||
self.assertEqual(sorted(expected, key=lambda model: model.id),
|
||||
self.assertEqual(
|
||||
sorted(expected, key=lambda model: model.id),
|
||||
sorted(actual, key=lambda model: model.id))
|
||||
|
||||
def assertUrlEqual(self, expected, actual):
|
||||
self.assertEqual(expected.partition("?")[0], actual.partition("?")[0])
|
||||
|
||||
#params ordering might be different in the urls
|
||||
self.assertEqual(urlparse.parse_qs(expected.partition("?")[2]),
|
||||
self.assertEqual(
|
||||
urlparse.parse_qs(expected.partition("?")[2]),
|
||||
urlparse.parse_qs(actual.partition("?")[2]))
|
||||
|
||||
def assertErrorResponse(self, response, error_type, expected_error):
|
||||
|
@ -86,7 +86,7 @@ class FakeGuest(object):
|
||||
return self.root_was_enabled
|
||||
|
||||
def _list_resource(self, resource, limit=None, marker=None,
|
||||
include_marker=False):
|
||||
include_marker=False):
|
||||
names = sorted([name for name in resource])
|
||||
if marker in names:
|
||||
if not include_marker:
|
||||
|
@ -38,11 +38,10 @@ class FakeFlavor(object):
|
||||
|
||||
@property
|
||||
def links(self):
|
||||
return [{
|
||||
"href": "http://localhost:8774/v2/"
|
||||
"5064d71eb09c47e1956cf579822bae9a/flavors/%s" % self.id,
|
||||
"rel": link_type
|
||||
} for link_type in ['self', 'bookmark']]
|
||||
url = ("http://localhost:8774/v2/5064d71eb09c47e1956cf579822bae9a/"
|
||||
"flavors/%s") % self.id
|
||||
return [{"href": url, "rel": link_type}
|
||||
for link_type in ['self', 'bookmark']]
|
||||
|
||||
@property
|
||||
def href_suffix(self):
|
||||
@ -136,7 +135,7 @@ class FakeServer(object):
|
||||
# TODO(pdmars): This is less than ideal, but a quick way to force it
|
||||
# into the error state before scheduling the delete.
|
||||
if (self.name.endswith("_DELETE_ERROR") and
|
||||
self._current_status != "SHUTDOWN"):
|
||||
self._current_status != "SHUTDOWN"):
|
||||
# Fail to delete properly the first time, just set the status
|
||||
# to SHUTDOWN and break. It's important that we only fail to delete
|
||||
# once in fake mode.
|
||||
@ -151,10 +150,9 @@ class FakeServer(object):
|
||||
|
||||
@property
|
||||
def links(self):
|
||||
return [{
|
||||
"href": "https://localhost:9999/v1.0/1234/instances/%s" % self.id,
|
||||
"rel": link_type
|
||||
} for link_type in ['self', 'bookmark']]
|
||||
url = "https://localhost:9999/v1.0/1234/instances/%s" % self.id
|
||||
return [{"href": url, "rel": link_type}
|
||||
for link_type in ['self', 'bookmark']]
|
||||
|
||||
def resize(self, new_flavor_id):
|
||||
self._current_status = "RESIZE"
|
||||
@ -212,8 +210,8 @@ class FakeServers(object):
|
||||
def can_see(self, id):
|
||||
"""Can this FakeServers, with its context, see some resource?"""
|
||||
server = self.db[id]
|
||||
return self.context.is_admin or \
|
||||
server.owner.tenant == self.context.tenant
|
||||
return (self.context.is_admin or
|
||||
server.owner.tenant == self.context.tenant)
|
||||
|
||||
def create(self, name, image_id, flavor_ref, files=None,
|
||||
block_device_mapping=None, volume=None):
|
||||
@ -253,8 +251,8 @@ class FakeServers(object):
|
||||
mapping = block_device_mapping[device]
|
||||
(id, _type, size, delete_on_terminate) = mapping.split(":")
|
||||
volume = self.volumes.get(id)
|
||||
volume.mapping = FakeBlockDeviceMappingInfo(id, device,
|
||||
_type, size, delete_on_terminate)
|
||||
volume.mapping = FakeBlockDeviceMappingInfo(
|
||||
id, device, _type, size, delete_on_terminate)
|
||||
volumes.append(volume)
|
||||
return volumes
|
||||
|
||||
@ -359,10 +357,11 @@ class FakeVolume(object):
|
||||
self.device = "/var/lib/mysql"
|
||||
|
||||
def __repr__(self):
|
||||
return ("FakeVolume(id=%s, size=%s, "
|
||||
"display_name=%s, display_description=%s, _current_status=%s)"
|
||||
% (self.id, self.size, self.display_name,
|
||||
self.display_description, self._current_status))
|
||||
msg = ("FakeVolume(id=%s, size=%s, display_name=%s, "
|
||||
"display_description=%s, _current_status=%s)")
|
||||
params = (self.id, self.size, self.display_name,
|
||||
self.display_description, self._current_status)
|
||||
return (msg % params)
|
||||
|
||||
@property
|
||||
def availability_zone(self):
|
||||
@ -417,8 +416,8 @@ class FakeVolumes(object):
|
||||
def can_see(self, id):
|
||||
"""Can this FakeVolumes, with its context, see some resource?"""
|
||||
server = self.db[id]
|
||||
return self.context.is_admin or \
|
||||
server.owner.tenant == self.context.tenant
|
||||
return (self.context.is_admin or
|
||||
server.owner.tenant == self.context.tenant)
|
||||
|
||||
def get(self, id):
|
||||
if id not in self.db:
|
||||
@ -526,7 +525,7 @@ class FakeHost(object):
|
||||
'uuid': server.id,
|
||||
'name': server.name,
|
||||
'status': server.status
|
||||
})
|
||||
})
|
||||
try:
|
||||
flavor = FLAVORS.get(server.flavor_ref)
|
||||
except ValueError:
|
||||
|
@ -29,8 +29,8 @@ class ContextTest(unittest.TestCase):
|
||||
|
||||
def test_get_context_as_dict(self):
|
||||
ctx = context.ReddwarfContext(user=USER, tenant=TENANT,
|
||||
is_admin=True, show_deleted=True,
|
||||
read_only=True, auth_tok=AUTH_TOK)
|
||||
is_admin=True, show_deleted=True,
|
||||
read_only=True, auth_tok=AUTH_TOK)
|
||||
ctx_dict = ctx.to_dict()
|
||||
self.assertEqual(ctx_dict['user'], USER)
|
||||
self.assertEqual(ctx_dict['tenant'], TENANT)
|
||||
@ -40,9 +40,14 @@ class ContextTest(unittest.TestCase):
|
||||
self.assertEqual(ctx_dict['auth_tok'], AUTH_TOK)
|
||||
|
||||
def test_creating_context(self):
|
||||
tmp_ctx_dict = {'user': USER, 'tenant': TENANT, 'is_admin': True,
|
||||
'show_deleted': True, 'read_only': True,
|
||||
'auth_tok': AUTH_TOK}
|
||||
tmp_ctx_dict = {
|
||||
'user': USER,
|
||||
'tenant': TENANT,
|
||||
'is_admin': True,
|
||||
'show_deleted': True,
|
||||
'read_only': True,
|
||||
'auth_tok': AUTH_TOK,
|
||||
}
|
||||
tmp_ctx = context.ReddwarfContext.from_dict(tmp_ctx_dict)
|
||||
self.assertEqual(tmp_ctx.user, USER)
|
||||
self.assertEqual(tmp_ctx.tenant, TENANT)
|
||||
|
@ -46,22 +46,24 @@ class TestInstance(tests.BaseTest):
|
||||
self.FAKE_SERVER.id = self.expected_id
|
||||
self.FAKE_SERVER.flavor = ('http://localhost/1234/flavors/',
|
||||
'52415800-8b69-11e0-9b19-734f1195ff37')
|
||||
self.FAKE_SERVER.links = [{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "bookmark"
|
||||
}]
|
||||
self.FAKE_SERVER.links = [
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "self",
|
||||
},
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "bookmark",
|
||||
},
|
||||
]
|
||||
self.FAKE_SERVER.addresses = {
|
||||
"private": [
|
||||
{
|
||||
"addr": "10.0.0.4",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
"private": [
|
||||
{
|
||||
"addr": "10.0.0.4",
|
||||
"version": 4
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
client = self.mock.CreateMock(novaclient.v1_1.Client)
|
||||
servers = self.mock.CreateMock(novaclient.v1_1.servers.ServerManager)
|
||||
|
@ -33,22 +33,26 @@ class ControllerTestBase(tests.BaseTest):
|
||||
|
||||
def setUp(self):
|
||||
super(ControllerTestBase, self).setUp()
|
||||
conf, reddwarf_app = config.Config.load_paste_app('reddwarfapp',
|
||||
{"config_file": tests.test_config_file()}, None)
|
||||
conf, reddwarf_app = config.Config.load_paste_app(
|
||||
'reddwarfapp',
|
||||
{"config_file": tests.test_config_file()},
|
||||
None)
|
||||
self.app = unit.TestApp(reddwarf_app)
|
||||
|
||||
|
||||
class TestInstanceController(ControllerTestBase):
|
||||
|
||||
DUMMY_INSTANCE_ID = "123"
|
||||
DUMMY_INSTANCE = {"id": DUMMY_INSTANCE_ID,
|
||||
"name": "DUMMY_NAME",
|
||||
"status": "BUILD",
|
||||
"created": "createtime",
|
||||
"updated": "updatedtime",
|
||||
"flavor": {},
|
||||
"links": [],
|
||||
"addresses": {}}
|
||||
DUMMY_INSTANCE = {
|
||||
"id": DUMMY_INSTANCE_ID,
|
||||
"name": "DUMMY_NAME",
|
||||
"status": "BUILD",
|
||||
"created": "createtime",
|
||||
"updated": "updatedtime",
|
||||
"flavor": {},
|
||||
"links": [],
|
||||
"addresses": {},
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
self.instances_path = "/tenant/instances"
|
||||
@ -72,7 +76,7 @@ class TestInstanceController(ControllerTestBase):
|
||||
|
||||
response = self.app.get("%s/%s" % (self.instances_path,
|
||||
self.DUMMY_INSTANCE_ID),
|
||||
headers={'X-Auth-Token': '123'})
|
||||
headers={'X-Auth-Token': '123'})
|
||||
|
||||
self.assertEqual(response.status_int, 201)
|
||||
|
||||
@ -84,7 +88,7 @@ class TestInstanceController(ControllerTestBase):
|
||||
models.Instances.__init__(mox.IgnoreArg())
|
||||
self.mock.ReplayAll()
|
||||
response = self.app.get("%s" % (self.instances_path),
|
||||
headers={'X-Auth-Token': '123'})
|
||||
headers={'X-Auth-Token': '123'})
|
||||
self.assertEqual(response.status_int, 201)
|
||||
|
||||
def mock_out_client_create(self):
|
||||
@ -98,22 +102,24 @@ class TestInstanceController(ControllerTestBase):
|
||||
self.FAKE_SERVER.created = utils.utcnow()
|
||||
self.FAKE_SERVER.id = utils.generate_uuid()
|
||||
self.FAKE_SERVER.flavor = 'http://localhost/1234/flavors/1234'
|
||||
self.FAKE_SERVER.links = [{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "bookmark"
|
||||
}]
|
||||
self.FAKE_SERVER.addresses = {
|
||||
"private": [
|
||||
{
|
||||
"addr": "10.0.0.4",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
self.FAKE_SERVER.links = [
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "self",
|
||||
},
|
||||
{
|
||||
"href": "http://localhost/1234/instances/123",
|
||||
"rel": "bookmark",
|
||||
}
|
||||
]
|
||||
self.FAKE_SERVER.addresses = {
|
||||
"private": [
|
||||
{
|
||||
"addr": "10.0.0.4",
|
||||
"version": 4,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
client = self.mock.CreateMock(novaclient.v1_1.Client)
|
||||
servers = self.mock.CreateMock(novaclient.v1_1.servers.ServerManager)
|
||||
@ -131,8 +137,8 @@ class TestInstanceController(ControllerTestBase):
|
||||
models.Instance.data().AndReturn(self.DUMMY_INSTANCE)
|
||||
|
||||
self.mock.StubOutWithMock(models.ServiceImage, 'find_by')
|
||||
models.ServiceImage.find_by(service_name=mox.IgnoreArg()).AndReturn(
|
||||
{'image_id': 1234})
|
||||
models.ServiceImage.find_by(
|
||||
service_name=mox.IgnoreArg()).AndReturn({'image_id': 1234})
|
||||
|
||||
self.mock_out_client_create()
|
||||
self.mock.ReplayAll()
|
||||
@ -154,7 +160,6 @@ class TestInstanceController(ControllerTestBase):
|
||||
}
|
||||
}
|
||||
response = self.app.post_json("%s" % (self.instances_path), body=body,
|
||||
headers={'X-Auth-Token': '123'},
|
||||
)
|
||||
headers={'X-Auth-Token': '123'})
|
||||
print(response)
|
||||
self.assertEqual(response.status_int, 201)
|
||||
|
@ -72,7 +72,7 @@ class VersionedURLMapTest(tests.BaseTest):
|
||||
environ = {
|
||||
'HTTP_ACCEPT': "application/json;version=1.0",
|
||||
'PATH_INFO': "/resource",
|
||||
}
|
||||
}
|
||||
|
||||
self.versioned_urlmap(environ=environ, start_response=None)
|
||||
|
||||
@ -83,7 +83,7 @@ class VersionedURLMapTest(tests.BaseTest):
|
||||
'HTTP_ACCEPT': "application/vnd.openstack.reddwarf+xml;"
|
||||
"version=9.0", 'REQUEST_METHOD': "GET",
|
||||
'PATH_INFO': "/resource.xml",
|
||||
}
|
||||
}
|
||||
|
||||
def assert_status(status, *args):
|
||||
self.assertEqual(status, "406 Not Acceptable")
|
||||
@ -95,7 +95,7 @@ class VersionedURLMapTest(tests.BaseTest):
|
||||
'HTTP_ACCEPT': "application/vnd.openstack.reddwarf+xml;"
|
||||
"version=2.0",
|
||||
'PATH_INFO': "/v1.0/resource",
|
||||
}
|
||||
}
|
||||
|
||||
self.versioned_urlmap(environ=environ, start_response=None)
|
||||
|
||||
|
@ -38,8 +38,11 @@ class VersionsController(wsgi.Controller):
|
||||
"""Respond to a request for API versions."""
|
||||
versions = []
|
||||
for key, data in VERSIONS.items():
|
||||
v = BaseVersion(data["id"], data["status"],
|
||||
request.application_url, data["updated"])
|
||||
v = BaseVersion(
|
||||
data["id"],
|
||||
data["status"],
|
||||
request.application_url,
|
||||
data["updated"])
|
||||
versions.append(v)
|
||||
return wsgi.Result(VersionsDataView(versions))
|
||||
|
||||
@ -60,10 +63,12 @@ class BaseVersion(object):
|
||||
self.updated = updated
|
||||
|
||||
def data(self):
|
||||
return dict(id=self.id,
|
||||
status=self.status,
|
||||
updated=self.updated,
|
||||
links=[dict(rel="self", href=self.url())])
|
||||
return {
|
||||
"id": self.id,
|
||||
"status": self.status,
|
||||
"updated": self.updated,
|
||||
"links": [{"rel": "self", "href": self.url()}],
|
||||
}
|
||||
|
||||
def url(self):
|
||||
url = os.path.join(self.base_url, self.id)
|
||||
|
Loading…
Reference in New Issue
Block a user