Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial lock functionality commit

  • Loading branch information...
commit 8aea573bd2e44e152fb4ef1627640bab1818dede 1 parent 675ca7c
@tr3buchet tr3buchet authored
View
73 nova/api/openstack/__init__.py
@@ -22,6 +22,7 @@
import json
import time
+import functools
import logging
import routes
@@ -113,3 +114,75 @@ def __init__(self):
controller=sharedipgroups.Controller())
super(APIRouter, self).__init__(mapper)
+
+
+#class CheckLock(object):
+# """
+# decorator used for preventing action against locked instances
+# unless, of course, you happen to be admin
+#
+# """
+# def __init__(self, function):
+# self.function = function
+#
+# def __getattribute__(self, attr):
+# if attr == "function":
+# return super(CheckLock, self).__getattribute__(attr)
+# return self.function.__getattribute__(attr)
+#
+# def __call__(self, *args, **kwargs):
+# logging.info(_("Calling %s. Checking locks and privileges"),
+# self.function.__name__)
+#
+# # get req
+# if 'req' is in kwargs:
+# req = kwargs['req']
+# else:
+# req = args[1]
+#
+# # check table for lock
+# locked = True
+# if(locked):
+# # check context for admin
+# if(req.environ['nova.context'].is_admin):
+# self.function(*args, **kwargs)
+# else:
+# pass
+# # return 404
+#
+# def __get__(self, obj, objtype):
+# f = functools.partial(self.__call__, obj)
+# f.__doc__ = self.function.__doc__
+# return f
+
+
+
+
+#def checks_lock(function):
+# """
+# decorator used for preventing action against locked instances
+# unless, of course, you happen to be admin
+#
+# """
+#
+# @functools.wraps(function)
+# def decorated_function(*args, **kwargs):
+#
+# # check table for lock
+# locked = True
+# if(locked):
+# try:
+# # get context from req and check for admin
+# if 'req' is in kwargs:
+# req = kwargs['req']
+# else:
+# req = args[1]
+# if(req.environ['nova.context'].is_admin):
+# function(*args, **kwargs)
+# else:
+# pass
+# # return 404
+# except:
+# logging.error(_("CheckLock: error getting context"))
+#
+# return decorated_function
View
86 nova/api/openstack/servers.py
@@ -35,6 +35,40 @@
LOG.setLevel(logging.DEBUG)
+def checks_lock(function):
+ """
+ decorator used for preventing action against locked instances
+ unless, of course, you happen to be admin
+
+ """
+
+ @functools.wraps(function)
+ def decorated_function(*args, **kwargs):
+
+ # grab args to function
+ try:
+ if 'req' is in kwargs:
+ req = kwargs['req']
+ else:
+ req = args[1]
+ if 'id' is in kwargs:
+ _id = kwargs['id']
+ else:
+ req = args[2]
+ context = req.environ['nova.context']
+ except:
+ logging.error(_("CheckLock: argument error"))
+
+ # if locked and admin call function, otherwise 404
+ if(compute_api.ComputeAPI().get_lock(context, _id)):
+ if(req.environ['nova.context'].is_admin):
+ function(*args, **kwargs)
+ # return 404
+ return faults.Fault(exc.HTTPUnprocessableEntity())
+
+ return decorated_function
+
+
def _entity_list(entities):
""" Coerces a list of servers into proper dictionary format """
return dict(servers=entities)
@@ -104,6 +138,7 @@ def _items(self, req, entity_maker):
res = [entity_maker(inst)['server'] for inst in limited_list]
return _entity_list(res)
+ @checks_lock
def show(self, req, id):
""" Returns server details by server id """
try:
@@ -113,6 +148,7 @@ def show(self, req, id):
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
+ @checks_lock
def delete(self, req, id):
""" Destroys a server """
try:
@@ -140,6 +176,7 @@ def create(self, req):
key_data=key_pair['public_key'])
return _entity_inst(instances[0])
+ @checks_lock
def update(self, req, id):
""" Updates the server name or password """
inst_dict = self._deserialize(req.body, req)
@@ -160,6 +197,7 @@ def update(self, req, id):
return faults.Fault(exc.HTTPNotFound())
return exc.HTTPNoContent()
+ @checks_lock
def action(self, req, id):
""" Multi-purpose method used to reboot, rebuild, and
resize a server """
@@ -176,6 +214,51 @@ def action(self, req, id):
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
+ def lock(self, req, id):
+ """
+ lock the instance with id
+ admin only operation
+
+ """
+ context = req.environ['nova.context']
+ try:
+ self.compute_api.lock(context, id)
+ except:
+ readable = traceback.format_exc()
+ logging.error(_("Compute.api::lock %s"), readable)
+ return faults.Fault(exc.HTTPUnprocessableEntity())
+ return exc.HTTPAccepted()
+
+ def unlock(self, req, id):
+ """
+ unlock the instance with id
+ admin only operation
+
+ """
+ context = req.environ['nova.context']
+ try:
+ self.compute_api.unlock(context, id)
+ except:
+ readable = traceback.format_exc()
+ logging.error(_("Compute.api::unlock %s"), readable)
+ return faults.Fault(exc.HTTPUnprocessableEntity())
+ return exc.HTTPAccepted()
+
+ def get_lock(self, req, id):
+ """
+ return the boolean state of (instance with id)'s lock
+
+ """
+ context = req.environ['nova.context']
+ try:
+ self.compute_api.get_lock(context, id)
+ except:
+ readable = traceback.format_exc()
+ logging.error(_("Compute.api::get_lock %s"), readable)
+ return faults.Fault(exc.HTTPUnprocessableEntity())
+ return exc.HTTPAccepted()
+
+ @checks_lock
def pause(self, req, id):
""" Permit Admins to Pause the server. """
ctxt = req.environ['nova.context']
@@ -187,6 +270,7 @@ def pause(self, req, id):
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
+ @checks_lock
def unpause(self, req, id):
""" Permit Admins to Unpause the server. """
ctxt = req.environ['nova.context']
@@ -198,6 +282,7 @@ def unpause(self, req, id):
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
+ @checks_lock
def suspend(self, req, id):
"""permit admins to suspend the server"""
context = req.environ['nova.context']
@@ -209,6 +294,7 @@ def suspend(self, req, id):
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
+ @checks_lock
def resume(self, req, id):
"""permit admins to resume the server from suspend"""
context = req.environ['nova.context']
View
35 nova/compute/api.py
@@ -141,7 +141,8 @@ def create_instances(self, context, instance_type, image_id, min_count=1,
'display_description': description,
'user_data': user_data or '',
'key_name': key_name,
- 'key_data': key_data}
+ 'key_data': key_data,
+ 'locked': False}
elevated = context.elevated()
instances = []
@@ -319,3 +320,35 @@ def unrescue(self, context, instance_id):
self.db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "unrescue_instance",
"args": {"instance_id": instance['id']}})
+
+ def lock(self, context, instance_id):
+ """
+ lock the instance with instance_id
+
+ """
+ instance = self.get_instance(context, instance_id)
+ host = instance['host']
+ rpc.cast(context,
+ self.db.queue_get_for(context, FLAGS.compute_topic, host),
+ {"method": "lock_instance",
+ "args": {"instance_id": instance['id']}})
+
+ def unlock(self, context, instance_id):
+ """
+ unlock the instance with instance_id
+
+ """
+ instance = self.get_instance(context, instance_id)
+ host = instance['host']
+ rpc.cast(context,
+ self.db.queue_get_for(context, FLAGS.compute_topic, host),
+ {"method": "unlock_instance",
+ "args": {"instance_id": instance['id']}})
+
+ def get_lock(self, context, instance_id):
+ """
+ return the boolean state of (instance with instance_id)'s lock
+
+ """
+ instance = self.get_instance(context, instance_id)
+ return instance['locked']
View
24 nova/compute/manager.py
@@ -330,6 +330,30 @@ def resume_instance(self, context, instance_id):
result))
@exception.wrap_exception
+ def lock_instance(self, context, instance_id):
+ """
+ lock the instance with instance_id
+
+ """
+ context = context.elevated()
+ instance_ref = self.db.instance_get(context, instance_id)
+
+ logging.debug(_('instance %s: locking'), instance_ref['internal_id'])
+ self.db.instance_set_lock(context, instance_id, True)
+
+ @exception.wrap_exception
+ def unlock_instance(self, context, instance_id):
+ """
+ unlock the instance with instance_id
+
+ """
+ context = context.elevated()
+ instance_ref = self.db.instance_get(context, instance_id)
+
+ logging.debug(_('instance %s: unlocking'), instance_ref['internal_id'])
+ self.db.instance_set_lock(context, instance_id, False)
+
+ @exception.wrap_exception
def get_console_output(self, context, instance_id):
"""Send the console output for an instance."""
context = context.elevated()
View
22 nova/db/sqlalchemy/api.py
@@ -856,6 +856,28 @@ def instance_action_create(context, values):
return action_ref
+@require_admin_context
+def instance_set_lock(context, instance_id, lock):
+ """
+ twiddle the locked bit in the db
+ lock is a boolean
+
+ """
+ db.instance_update(context,
+ instance_id,
+ {'locked': lock})
+
+
+#@require_admin_context
+#def instance_is_locked(context, instance_id):
+# """
+# return the boolean state of (instance with instance_id)'s lock
+#
+# """
+# instance_ref = instance_get(context, instance_id)
+# return instance_ref['locked']
+
+
###################
View
2  nova/db/sqlalchemy/models.py
@@ -224,6 +224,8 @@ def name(self):
display_name = Column(String(255))
display_description = Column(String(255))
+ locked = Column(Boolean)
+
# TODO(vish): see Ewan's email about state improvements, probably
# should be in a driver base class or some such
# vmstate_state = running, halted, suspended, paused
Please sign in to comment.
Something went wrong with that request. Please try again.