Deal with cinder-backup service absent

cinder-backup service is optional, and currently not discoverable with
non-admin scoped tokens.

This patch introduces a new config option `volumes.backups_enabled`
(defaults to True for backward compat).
When set to False, it will fail validation of stacks containing volume
resources with deletion_policy set to Snapshot,
as such stacks will be undeletable in the absence of cinder-backup
service.

Change-Id: I10c4787870e7b240d775aa5d66eb1d0a6d837d8d
Partial-Bug: #1595159
This commit is contained in:
Pavlo Shchelokovskyy 2016-06-22 17:02:58 +03:00
parent 0864664209
commit 744527f6ab
6 changed files with 58 additions and 4 deletions

View File

@ -195,6 +195,10 @@ function configure_heat {
iniset $HEAT_CONF cache enabled "True"
iniset $HEAT_CONF cache backend "dogpile.cache.memory"
if ! is_service_enabled c-bak; then
iniset $HEAT_CONF volumes backups_enabled false
fi
sudo install -d -o $STACK_USER $HEAT_ENV_DIR $HEAT_TEMPLATES_DIR
# copy the default environment

View File

@ -344,6 +344,14 @@ revision_opts = [
'separately, you can move this section to a different '
'file and add it as another config option.'))]
volumes_group = cfg.OptGroup('volumes')
volumes_opts = [
cfg.BoolOpt('backups_enabled',
default=True,
help=_("Indicate if cinder-backup service is enabled. "
"This is a temporary workaround until cinder-backup "
"service becomes discoverable, see LP#1334856."))]
def startup_sanity_check():
if (not cfg.CONF.stack_user_domain_id and
@ -377,6 +385,7 @@ def list_opts():
yield paste_deploy_group.name, paste_deploy_opts
yield auth_password_group.name, auth_password_opts
yield revision_group.name, revision_opts
yield volumes_group.name, volumes_opts
yield profiler.list_opts()[0]
yield 'clients', default_clients_opts

View File

@ -11,10 +11,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from heat.common import exception
from heat.common.i18n import _
from heat.engine.clients import progress
from heat.engine import resource
from heat.engine import rsrc_defn
class BaseVolume(resource.Resource):
@ -159,6 +162,17 @@ class BaseVolume(resource.Resource):
return False
return True
@classmethod
def validate_deletion_policy(cls, policy):
res = super(BaseVolume, cls).validate_deletion_policy(policy)
if res:
return res
if (policy == rsrc_defn.ResourceDefinition.SNAPSHOT and
not cfg.CONF.volumes.backups_enabled):
msg = _('"%s" deletion policy not supported - '
'volume backup service is not enabled.') % policy
raise exception.StackValidationFailed(message=msg)
class BaseVolumeAttachment(resource.Resource):
"""Base Volume Attachment Manager."""

View File

@ -736,3 +736,14 @@ class VolumeTest(vt_base.BaseVolumeTest):
six.text_type(ex))
self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
self.m.VerifyAll()
def test_vaildate_deletion_policy(self):
cfg.CONF.set_override('backups_enabled', False, group='volumes')
stack_name = 'test_volume_validate_deletion_policy'
self.t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
stack = utils.parse_stack(self.t, stack_name=stack_name)
rsrc = self.get_volume(self.t, stack, 'DataVolume')
self.assertRaisesRegex(
exception.StackValidationFailed,
'volume backup service is not enabled',
rsrc.validate)

View File

@ -16,6 +16,7 @@ import copy
import json
from cinderclient import exceptions as cinder_exp
from oslo_config import cfg
import six
from heat.common import exception
@ -1247,3 +1248,14 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
stack.t.resource_definitions(stack)['volume'],
stack)
self.assertIsNone(rsrc.handle_delete_snapshot(mock_vs))
def test_vaildate_deletion_policy(self):
cfg.CONF.set_override('backups_enabled', False, group='volumes')
stack_name = 'test_volume_validate_deletion_policy'
self.t['resources']['volume']['deletion_policy'] = 'Snapshot'
stack = utils.parse_stack(self.t, stack_name=stack_name)
rsrc = self.get_volume(self.t, stack, 'volume')
self.assertRaisesRegex(
exception.StackValidationFailed,
'volume backup service is not enabled',
rsrc.validate)

View File

@ -64,16 +64,20 @@ class BaseVolumeTest(common.HeatTestCase):
self.cinder_fc.volumes.get(fva.id).AndReturn(fv_ready)
return fv_ready
def create_volume(self, t, stack, resource_name):
def get_volume(self, t, stack, resource_name):
if self.use_cinder:
Volume = os_vol.CinderVolume
else:
data = t['Resources'][resource_name]
data['Properties']['AvailabilityZone'] = 'nova'
Volume = aws_vol.Volume
rsrc = Volume(resource_name,
vol = Volume(resource_name,
stack.t.resource_definitions(stack)[resource_name],
stack)
return vol
def create_volume(self, t, stack, resource_name):
rsrc = self.get_volume(t, stack, resource_name)
self.assertIsNone(rsrc.validate())
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)