Refactor SignalResponder to abstract user logic

Refactor to abstract the logic related to managing the user and
keypair, so in a future patch we can migrate to stack domain users.

Change-Id: Id112fdadcfa2cf1f47f00f93750110ec680a803e
blueprint: instance-users
This commit is contained in:
Steven Hardy 2014-02-10 17:34:41 +00:00
parent 710a958076
commit 8a02562545
2 changed files with 93 additions and 42 deletions

View File

@ -16,11 +16,10 @@
from oslo.config import cfg
from keystoneclient.contrib.ec2 import utils as ec2_utils
import keystoneclient.exceptions as kc_exception
from heat.db import api as db_api
from heat.common import exception
from heat.engine import resource
from heat.engine import stack_user
from heat.openstack.common import log as logging
from heat.openstack.common.gettextutils import _
@ -38,55 +37,21 @@ SIGNAL_VERB = {WAITCONDITION: 'PUT',
SIGNAL: 'POST'}
class SignalResponder(resource.Resource):
class SignalResponder(stack_user.StackUser):
# Anything which subclasses this may trigger authenticated
# API operations as a consequence of handling a signal
requires_deferred_auth = True
def handle_create(self):
# Create a keystone user so we can create a signed URL via FnGetRefId
user_id = self.keystone().create_stack_user(
self.physical_resource_name())
db_api.resource_data_set(self, 'user_id', user_id)
kp = self.keystone().create_ec2_keypair(user_id)
if not kp:
raise exception.Error(_("Error creating ec2 keypair for user %s") %
user_id)
else:
db_api.resource_data_set(self, 'credential_id', kp.id,
redact=True)
db_api.resource_data_set(self, 'access_key', kp.access,
redact=True)
db_api.resource_data_set(self, 'secret_key', kp.secret,
redact=True)
def _get_user_id(self):
try:
return db_api.resource_data_get(self, 'user_id')
except exception.NotFound:
# Assume this is a resource that was created with
# a previous version of heat and that the resource_id
# is the user_id
if self.resource_id:
db_api.resource_data_set(self, 'user_id', self.resource_id)
return self.resource_id
super(SignalResponder, self).handle_create()
self._create_keypair()
def handle_delete(self):
user_id = self._get_user_id()
if user_id is None:
return
super(SignalResponder, self).handle_delete()
try:
self.keystone().delete_stack_user(user_id)
except kc_exception.NotFound:
pass
for data_key in ('ec2_signed_url', 'access_key', 'secret_key',
'credential_id'):
try:
db_api.resource_data_delete(self, data_key)
except exception.NotFound:
db_api.resource_data_delete(self, 'ec2_signed_url')
except exception.NotFound:
pass
def _get_signed_url(self, signal_type=SIGNAL):

86
heat/engine/stack_user.py Normal file
View File

@ -0,0 +1,86 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import keystoneclient.exceptions as kc_exception
from heat.db import api as db_api
from heat.common import exception
from heat.engine import resource
from heat.openstack.common import log as logging
from heat.openstack.common.gettextutils import _
logger = logging.getLogger(__name__)
class StackUser(resource.Resource):
# Subclasses create a user, and optionally keypair
# associated with a resource in a stack
def handle_create(self):
self._create_user()
def _create_user(self):
user_id = self.keystone().create_stack_user(
self.physical_resource_name())
db_api.resource_data_set(self, 'user_id', user_id)
def _get_user_id(self):
try:
return db_api.resource_data_get(self, 'user_id')
except exception.NotFound:
# Assume this is a resource that was created with
# a previous version of heat and that the resource_id
# is the user_id
if self.resource_id:
db_api.resource_data_set(self, 'user_id', self.resource_id)
return self.resource_id
def handle_delete(self):
self._delete_user()
def _delete_user(self):
user_id = self._get_user_id()
if user_id is None:
return
try:
self.keystone().delete_stack_user(user_id)
except kc_exception.NotFound:
pass
for data_key in ('ec2_signed_url', 'access_key', 'secret_key',
'credential_id'):
try:
db_api.resource_data_delete(self, data_key)
except exception.NotFound:
pass
def _create_keypair(self):
# Subclasses may optionally call this in handle_create to create
# an ec2 keypair associated with the user, the resulting keys are
# stored in resource_data
user_id = self._get_user_id()
kp = self.keystone().create_ec2_keypair(user_id)
if not kp:
raise exception.Error(_("Error creating ec2 keypair for user %s") %
user_id)
else:
db_api.resource_data_set(self, 'credential_id', kp.id,
redact=True)
db_api.resource_data_set(self, 'access_key', kp.access,
redact=True)
db_api.resource_data_set(self, 'secret_key', kp.secret,
redact=True)