Status attributes for GBP resources

Adds attributes to reflect the opertaional status of a resource.

Also updates Policy Driver interface and Policy Plugin implementation
to conditionally allow policy drivers to pull and update status
in response to a GET.

Change-Id: I4f123d8b84125427032ebb9d75aad40b33617271
Implements: blueprint resource-status
This commit is contained in:
Sumit Naiksatam 2016-03-07 11:24:32 -08:00
parent 9519193d9c
commit 05a7709fb2
16 changed files with 862 additions and 433 deletions

3
.gitignore vendored
View File

@ -54,3 +54,6 @@ ChangeLog
*~
.*.swp
.*sw?
# Pycharm
.idea

View File

@ -34,18 +34,18 @@ MAX_IPV6_SUBNET_PREFIX_LENGTH = 127
ADDRESS_NOT_SPECIFIED = ''
class HasNameDescription(object):
class BaseGbpResource(models_v2.HasId, models_v2.HasTenant):
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
status = sa.Column(sa.String(length=16), nullable=True)
status_details = sa.Column(sa.String(length=4096), nullable=True)
class BaseSharedGbpResource(models_v2.HasId, models_v2.HasTenant,
HasNameDescription):
class BaseSharedGbpResource(BaseGbpResource):
shared = sa.Column(sa.Boolean)
pass
class PolicyTarget(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class PolicyTarget(model_base.BASEV2, BaseGbpResource):
"""Lowest unit of abstraction on which a policy is applied."""
__tablename__ = 'gp_policy_targets'
type = sa.Column(sa.String(15))
@ -53,8 +53,6 @@ class PolicyTarget(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
'polymorphic_on': type,
'polymorphic_identity': 'base'
}
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
policy_target_group_id = sa.Column(sa.String(36),
sa.ForeignKey(
'gp_policy_target_groups.id'),
@ -86,8 +84,7 @@ class PTGToPRSConsumingAssociation(model_base.BASEV2):
primary_key=True)
class PolicyTargetGroup(model_base.BASEV2,
models_v2.HasId, models_v2.HasTenant):
class PolicyTargetGroup(model_base.BASEV2, BaseSharedGbpResource):
"""It is a collection of policy_targets."""
__tablename__ = 'gp_policy_target_groups'
type = sa.Column(sa.String(15))
@ -95,8 +92,6 @@ class PolicyTargetGroup(model_base.BASEV2,
'polymorphic_on': type,
'polymorphic_identity': 'base'
}
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
policy_targets = orm.relationship(PolicyTarget,
backref='policy_target_group')
l2_policy_id = sa.Column(sa.String(36),
@ -111,11 +106,10 @@ class PolicyTargetGroup(model_base.BASEV2,
consumed_policy_rule_sets = orm.relationship(
PTGToPRSConsumingAssociation,
backref='consuming_policy_target_group', cascade='all, delete-orphan')
shared = sa.Column(sa.Boolean)
service_management = sa.Column(sa.Boolean)
class L2Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class L2Policy(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a L2 Policy for a collection of policy_target_groups."""
__tablename__ = 'gp_l2_policies'
type = sa.Column(sa.String(15))
@ -123,8 +117,6 @@ class L2Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
'polymorphic_on': type,
'polymorphic_identity': 'base'
}
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
policy_target_groups = orm.relationship(PolicyTargetGroup,
backref='l2_policy')
l3_policy_id = sa.Column(sa.String(36),
@ -132,7 +124,6 @@ class L2Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
nullable=True)
inject_default_route = sa.Column(sa.Boolean, default=True,
server_default=sa.sql.true())
shared = sa.Column(sa.Boolean)
class ESToL3PAssociation(model_base.BASEV2):
@ -147,7 +138,7 @@ class ESToL3PAssociation(model_base.BASEV2):
primary_key=True)
class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class L3Policy(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a L3 Policy with a non-overlapping IP address space."""
__tablename__ = 'gp_l3_policies'
type = sa.Column(sa.String(15))
@ -155,13 +146,10 @@ class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
'polymorphic_on': type,
'polymorphic_identity': 'base'
}
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
ip_version = sa.Column(sa.Integer, nullable=False)
ip_pool = sa.Column(sa.String(64), nullable=False)
subnet_prefix_length = sa.Column(sa.Integer, nullable=False)
l2_policies = orm.relationship(L2Policy, backref='l3_policy')
shared = sa.Column(sa.Boolean)
external_segments = orm.relationship(
ESToL3PAssociation, backref='l3_policies',
cascade='all, delete-orphan')
@ -178,18 +166,14 @@ class NetworkServiceParam(model_base.BASEV2, models_v2.HasId):
nullable=False)
class NetworkServicePolicy(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class NetworkServicePolicy(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a Network Service Policy."""
__tablename__ = 'gp_network_service_policies'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
policy_target_groups = orm.relationship(PolicyTargetGroup,
backref='network_service_policy')
network_service_params = orm.relationship(
NetworkServiceParam, backref='network_service_policy',
cascade='all, delete-orphan')
shared = sa.Column(sa.Boolean)
class PRSToPRAssociation(model_base.BASEV2):
@ -215,11 +199,9 @@ class PolicyRuleActionAssociation(model_base.BASEV2):
primary_key=True)
class PolicyRule(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class PolicyRule(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a Group Policy Rule."""
__tablename__ = 'gp_policy_rules'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
enabled = sa.Column(sa.Boolean)
policy_classifier_id = sa.Column(sa.String(36),
sa.ForeignKey(
@ -231,15 +213,11 @@ class PolicyRule(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
policy_rule_sets = orm.relationship(PRSToPRAssociation,
backref='policy_rule', lazy="joined",
cascade='all, delete-orphan')
shared = sa.Column(sa.Boolean)
class PolicyClassifier(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class PolicyClassifier(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a Group Policy Classifier."""
__tablename__ = 'gp_policy_classifiers'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
protocol = sa.Column(sa.String(50), nullable=True)
port_range_min = sa.Column(sa.Integer)
port_range_max = sa.Column(sa.Integer)
@ -249,14 +227,11 @@ class PolicyClassifier(model_base.BASEV2, models_v2.HasId,
name='direction'))
policy_rules = orm.relationship(PolicyRule,
backref='gp_policy_classifiers')
shared = sa.Column(sa.Boolean)
class PolicyAction(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class PolicyAction(model_base.BASEV2, BaseSharedGbpResource):
"""Represents a Group Policy Action."""
__tablename__ = 'gp_policy_actions'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
action_type = sa.Column(sa.Enum(gp_constants.GP_ACTION_ALLOW,
gp_constants.GP_ACTION_REDIRECT,
name='action_type'))
@ -266,7 +241,6 @@ class PolicyAction(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
action_value = sa.Column(sa.String(36), nullable=True)
policy_rules = orm.relationship(PolicyRuleActionAssociation,
cascade='all', backref='gp_policy_actions')
shared = sa.Column(sa.Boolean)
class EPToPRSProvidingAssociation(model_base.BASEV2):
@ -319,6 +293,8 @@ class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
EPToPRSConsumingAssociation,
backref='consumed_policy_rule_set', lazy="joined", cascade='all')
shared = sa.Column(sa.Boolean)
status = sa.Column(sa.String(length=16), nullable=True)
status_details = sa.Column(sa.String(length=4096), nullable=True)
class NATPool(model_base.BASEV2, BaseSharedGbpResource):
@ -794,24 +770,32 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
l3_policy_id=l3p_db['id'], allocated_address=ip)
l3p_db.external_segments.append(assoc)
def _populate_common_fields_in_dict(self, db_ref):
res = {'id': db_ref['id'],
'tenant_id': db_ref['tenant_id'],
'name': db_ref['name'],
'description': db_ref['description'],
'status': db_ref['status'],
'status_details': db_ref['status_details'],
'shared': db_ref.get('shared', False)}
return res
def _make_policy_target_dict(self, pt, fields=None):
res = {'id': pt['id'],
'tenant_id': pt['tenant_id'],
'name': pt['name'],
'description': pt['description'],
'status': pt['status'],
'status_details': pt['status_details'],
'policy_target_group_id': pt['policy_target_group_id'],
'cluster_id': pt['cluster_id']}
return self._fields(res, fields)
def _make_policy_target_group_dict(self, ptg, fields=None):
res = {'id': ptg['id'],
'tenant_id': ptg['tenant_id'],
'name': ptg['name'],
'description': ptg['description'],
'l2_policy_id': ptg['l2_policy_id'],
'network_service_policy_id': ptg['network_service_policy_id'],
'shared': ptg.get('shared', False),
'service_management': ptg.get('service_management', False)}
res = self._populate_common_fields_in_dict(ptg)
res['l2_policy_id'] = ptg['l2_policy_id']
res['network_service_policy_id'] = ptg['network_service_policy_id']
res['service_management'] = ptg.get('service_management', False)
res['policy_targets'] = [
pt['id'] for pt in ptg['policy_targets']]
res['provided_policy_rule_sets'] = (
@ -823,27 +807,18 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_l2_policy_dict(self, l2p, fields=None):
res = {'id': l2p['id'],
'tenant_id': l2p['tenant_id'],
'name': l2p['name'],
'description': l2p['description'],
'l3_policy_id': l2p['l3_policy_id'],
'inject_default_route': l2p.get('inject_default_route', True),
'shared': l2p.get('shared', False), }
res = self._populate_common_fields_in_dict(l2p)
res['l3_policy_id'] = l2p['l3_policy_id']
res['inject_default_route'] = l2p.get('inject_default_route', True)
res['policy_target_groups'] = [
ptg['id'] for ptg in l2p['policy_target_groups']]
return self._fields(res, fields)
def _make_l3_policy_dict(self, l3p, fields=None):
res = {'id': l3p['id'],
'tenant_id': l3p['tenant_id'],
'name': l3p['name'],
'description': l3p['description'],
'ip_version': l3p['ip_version'],
'ip_pool': l3p['ip_pool'],
'subnet_prefix_length':
l3p['subnet_prefix_length'],
'shared': l3p.get('shared', False), }
res = self._populate_common_fields_in_dict(l3p)
res['ip_version'] = l3p['ip_version']
res['ip_pool'] = l3p['ip_pool']
res['subnet_prefix_length'] = l3p['subnet_prefix_length']
res['l2_policies'] = [l2p['id']
for l2p in l3p['l2_policies']]
es_dict = {}
@ -856,11 +831,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_network_service_policy_dict(self, nsp, fields=None):
res = {'id': nsp['id'],
'tenant_id': nsp['tenant_id'],
'name': nsp['name'],
'description': nsp['description'],
'shared': nsp.get('shared', False), }
res = self._populate_common_fields_in_dict(nsp)
res['policy_target_groups'] = [
ptg['id'] for ptg in nsp['policy_target_groups']]
params = []
@ -873,41 +844,29 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_policy_classifier_dict(self, pc, fields=None):
res = self._populate_common_fields_in_dict(pc)
port_range = self._get_port_range_from_min_max_ports(
pc['port_range_min'],
pc['port_range_max'])
res = {'id': pc['id'],
'tenant_id': pc['tenant_id'],
'name': pc['name'],
'description': pc['description'],
'protocol': pc['protocol'],
'port_range': port_range,
'direction': pc['direction'],
'shared': pc.get('shared', False), }
res['protocol'] = pc['protocol']
res['port_range'] = port_range
res['direction'] = pc['direction']
res['policy_rules'] = [pr['id']
for pr in pc['policy_rules']]
return self._fields(res, fields)
def _make_policy_action_dict(self, pa, fields=None):
res = {'id': pa['id'],
'tenant_id': pa['tenant_id'],
'name': pa['name'],
'description': pa['description'],
'action_type': pa['action_type'],
'action_value': pa['action_value'],
'shared': pa.get('shared', False), }
res = self._populate_common_fields_in_dict(pa)
res['action_type'] = pa['action_type']
res['action_value'] = pa['action_value']
res['policy_rules'] = [pr['policy_rule_id'] for
pr in pa['policy_rules']]
return self._fields(res, fields)
def _make_policy_rule_dict(self, pr, fields=None):
res = {'id': pr['id'],
'tenant_id': pr['tenant_id'],
'name': pr['name'],
'description': pr['description'],
'enabled': pr['enabled'],
'policy_classifier_id': pr['policy_classifier_id'],
'shared': pr.get('shared', False), }
res = self._populate_common_fields_in_dict(pr)
res['enabled'] = pr['enabled']
res['policy_classifier_id'] = pr['policy_classifier_id']
res['policy_actions'] = [pa['policy_action_id']
for pa in pr['policy_actions']]
res['policy_rule_sets'] = [prs['policy_rule_set_id'] for prs in
@ -915,11 +874,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_policy_rule_set_dict(self, prs, fields=None):
res = {'id': prs['id'],
'tenant_id': prs['tenant_id'],
'name': prs['name'],
'description': prs['description'],
'shared': prs.get('shared', False), }
res = self._populate_common_fields_in_dict(prs)
if prs['parent']:
res['parent_id'] = prs['parent']['id']
else:
@ -958,14 +913,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_external_segment_dict(self, es, fields=None):
res = {'id': es['id'],
'tenant_id': es['tenant_id'],
'name': es['name'],
'description': es['description'],
'shared': es.get('shared', False),
'ip_version': es['ip_version'],
'cidr': es['cidr'],
'port_address_translation': es['port_address_translation']}
res = self._populate_common_fields_in_dict(es)
res['ip_version'] = es['ip_version']
res['cidr'] = es['cidr']
res['port_address_translation'] = es['port_address_translation']
res['external_routes'] = [{'destination': er['destination'],
'nexthop': er['nexthop']} for er in
es['external_routes']]
@ -979,11 +930,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_external_policy_dict(self, ep, fields=None):
res = {'id': ep['id'],
'tenant_id': ep['tenant_id'],
'name': ep['name'],
'description': ep['description'],
'shared': ep.get('shared', False), }
res = self._populate_common_fields_in_dict(ep)
res['external_segments'] = [
es['external_segment_id']
for es in ep['external_segments']]
@ -996,14 +943,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
return self._fields(res, fields)
def _make_nat_pool_dict(self, np, fields=None):
res = {'id': np['id'],
'tenant_id': np['tenant_id'],
'name': np['name'],
'description': np['description'],
'shared': np.get('shared', False),
'ip_version': np['ip_version'],
'ip_pool': np['ip_pool'],
'external_segment_id': np['external_segment_id']}
res = self._populate_common_fields_in_dict(np)
res['ip_version'] = np['ip_version']
res['ip_pool'] = np['ip_pool']
res['external_segment_id'] = np['external_segment_id']
return self._fields(res, fields)
def _get_ptgs_for_providing_policy_rule_set(self, context,
@ -1116,7 +1059,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
name=pt['name'], description=pt['description'],
policy_target_group_id=pt['policy_target_group_id'],
cluster_id=pt['cluster_id'])
cluster_id=pt['cluster_id'],
status=pt.get('status'),
status_details=pt.get('status_details'))
context.session.add(pt_db)
return self._make_policy_target_dict(pt_db)
@ -1170,7 +1115,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
l2_policy_id=ptg['l2_policy_id'],
network_service_policy_id=ptg['network_service_policy_id'],
shared=ptg.get('shared', False),
service_management=ptg.get('service_management', False))
service_management=ptg.get('service_management', False),
status=ptg.get('status'),
status_details=ptg.get('status_details'))
context.session.add(ptg_db)
self._process_policy_rule_sets_for_ptg(context, ptg_db, ptg)
return self._make_policy_target_group_dict(ptg_db)
@ -1236,10 +1183,12 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
l2p_db = L2Policy(id=uuidutils.generate_uuid(),
tenant_id=tenant_id, name=l2p['name'],
description=l2p['description'],
l3_policy_id=l2p['l3_policy_id'],
l3_policy_id=l2p.get('l3_policy_id'),
inject_default_route=l2p.get(
'inject_default_route', True),
shared=l2p.get('shared', False))
shared=l2p.get('shared', False),
status=l2p.get('status'),
status_details=l2p.get('status_details'))
context.session.add(l2p_db)
return self._make_l2_policy_dict(l2p_db)
@ -1298,7 +1247,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
ip_version=l3p['ip_version'],
ip_pool=l3p['ip_pool'],
subnet_prefix_length=l3p['subnet_prefix_length'],
shared=l3p.get('shared', False))
shared=l3p.get('shared', False),
status=l3p.get('status'),
status_details=l3p.get('status_details'))
if 'external_segments' in l3p:
self._set_ess_for_l3p(context, l3p_db,
l3p['external_segments'])
@ -1361,7 +1312,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
tenant_id=tenant_id,
name=nsp['name'],
description=nsp['description'],
shared=nsp.get('shared', False))
shared=nsp.get('shared', False),
status=nsp.get('status'),
status_details=
nsp.get('status_details'))
context.session.add(nsp_db)
self._set_params_for_network_service_policy(
context, nsp_db, nsp)
@ -1431,7 +1385,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
port_range_min=port_min,
port_range_max=port_max,
direction=pc['direction'],
shared=pc.get('shared', False))
shared=pc.get('shared', False),
status=pc.get('status'),
status_details=
pc.get('status_details'))
context.session.add(pc_db)
return self._make_policy_classifier_dict(pc_db)
@ -1497,7 +1454,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
description=pa['description'],
action_type=pa['action_type'],
action_value=pa['action_value'],
shared=pa.get('shared', False))
shared=pa.get('shared', False),
status=pa.get('status'),
status_details=
pa.get('status_details'))
context.session.add(pa_db)
return self._make_policy_action_dict(pa_db)
@ -1552,7 +1512,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
description=pr['description'],
enabled=pr['enabled'],
policy_classifier_id=pr['policy_classifier_id'],
shared=pr.get('shared', False))
shared=pr.get('shared', False),
status=pr.get('status'),
status_details=pr.get('status_details'))
context.session.add(pr_db)
self._set_actions_for_rule(context, pr_db,
pr['policy_actions'])
@ -1612,7 +1574,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
tenant_id=tenant_id,
name=prs['name'],
description=prs['description'],
shared=prs.get('shared', False))
shared=prs.get('shared', False),
status=prs.get('status'),
status_details=prs.get('status_details'))
context.session.add(prs_db)
self._set_rules_for_policy_rule_set(context, prs_db,
prs['policy_rules'])
@ -1687,7 +1651,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
ep_db = ExternalPolicy(
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
name=ep['name'], description=ep['description'],
shared=ep.get('shared', False))
shared=ep.get('shared', False),
status=ep.get('status'),
status_details=ep.get('status_details'))
context.session.add(ep_db)
if 'external_segments' in ep:
self._set_ess_for_ep(context, ep_db,
@ -1751,7 +1717,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
name=es['name'], description=es['description'],
shared=es.get('shared', False), ip_version=es['ip_version'],
cidr=es['cidr'],
port_address_translation=es['port_address_translation'])
port_address_translation=es['port_address_translation'],
status=es.get('status'),
status_details=es.get('status_details'))
context.session.add(es_db)
if 'external_routes' in es:
self._process_segment_ers(context, es_db, es)
@ -1811,7 +1779,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
name=np['name'], description=np['description'],
shared=np.get('shared', False), ip_version=np['ip_version'],
ip_pool=np['ip_pool'],
external_segment_id=np['external_segment_id'])
external_segment_id=np['external_segment_id'],
status=np.get('status'),
status_details=np.get('status_details'))
context.session.add(np_db)
return self._make_nat_pool_dict(np_db)

View File

@ -331,6 +331,24 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
ptg_db.update(ptg)
return self._make_policy_target_group_dict(ptg_db)
@log.log_method_call
def get_policy_target_groups_count(self, context, filters=None):
return self._get_collection_count(context, PolicyTargetGroupMapping,
filters=filters)
@log.log_method_call
def get_policy_target_groups(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
marker_obj = self._get_marker_obj(context, 'policy_target_group',
limit, marker)
return self._get_collection(context, PolicyTargetGroupMapping,
self._make_policy_target_group_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
@log.log_method_call
def create_l2_policy(self, context, l2_policy):
l2p = l2_policy['l2_policy']

View File

@ -0,0 +1,46 @@
# 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.
"""add status attributes
Revision ID: 12c1bc8d7026
Revises: 31b399f08b1c
Create Date: 2016-03-08 15:28:57.170563
"""
# revision identifiers, used by Alembic.
revision = '12c1bc8d7026'
down_revision = '31b399f08b1c'
from alembic import op
import sqlalchemy as sa
def upgrade():
table_names = ['gp_policy_targets', 'gp_policy_target_groups',
'gp_l2_policies', 'gp_l3_policies', 'gp_policy_rules',
'gp_policy_classifiers', 'gp_policy_actions',
'gp_policy_rule_sets', 'gp_nat_pools',
'gp_network_service_policies',
'gp_external_segments', 'gp_external_policies', 'sc_nodes',
'sc_instances', 'sc_specs', 'service_profiles']
for tname in table_names:
op.add_column(tname, sa.Column('status', sa.String(length=16),
nullable=True))
op.add_column(tname, sa.Column('status_details',
sa.String(length=4096), nullable=True))
def downgrade():
pass

View File

@ -1 +1 @@
31b399f08b1c
12c1bc8d7026

View File

@ -36,6 +36,17 @@ MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
MAX_IPV6_SUBNET_PREFIX_LENGTH = 127
class BaseSCResource(models_v2.HasId, models_v2.HasTenant):
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
status = sa.Column(sa.String(length=16), nullable=True)
status_details = sa.Column(sa.String(length=4096), nullable=True)
class BaseSharedSCResource(BaseSCResource):
shared = sa.Column(sa.Boolean)
class SpecNodeAssociation(model_base.BASEV2):
"""Models one to many providing relation between Specs and Nodes."""
__tablename__ = 'sc_spec_node_associations'
@ -58,29 +69,22 @@ class InstanceSpecAssociation(model_base.BASEV2):
position = sa.Column(sa.Integer)
class ServiceChainNode(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class ServiceChainNode(model_base.BASEV2, BaseSharedSCResource):
"""ServiceChain Node"""
__tablename__ = 'sc_nodes'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
config = sa.Column(sa.TEXT)
specs = orm.relationship(SpecNodeAssociation,
backref="nodes",
cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
service_type = sa.Column(sa.String(50), nullable=True)
service_profile_id = sa.Column(
sa.String(36), sa.ForeignKey('service_profiles.id'),
nullable=True)
class ServiceChainInstance(model_base.BASEV2,
models_v2.HasId, models_v2.HasTenant):
class ServiceChainInstance(model_base.BASEV2, BaseSCResource):
"""Service chain instances"""
__tablename__ = 'sc_instances'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
config_param_values = sa.Column(sa.String(4096))
specs = orm.relationship(
InstanceSpecAssociation,
@ -103,13 +107,10 @@ class ServiceChainInstance(model_base.BASEV2,
nullable=True)
class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class ServiceChainSpec(model_base.BASEV2, BaseSharedSCResource):
""" ServiceChain Spec
"""
__tablename__ = 'sc_specs'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
nodes = orm.relationship(
SpecNodeAssociation,
backref='specs', cascade='all, delete, delete-orphan',
@ -119,18 +120,13 @@ class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
instances = orm.relationship(InstanceSpecAssociation,
backref="specs",
cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
class ServiceProfile(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
class ServiceProfile(model_base.BASEV2, BaseSharedSCResource):
""" Service Profile
"""
__tablename__ = 'service_profiles'
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
vendor = sa.Column(sa.String(50))
shared = sa.Column(sa.Boolean)
# Not using ENUM for less painful upgrades. Validation will happen at the
# API level
insertion_mode = sa.Column(sa.String(50))
@ -188,26 +184,28 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
raise schain.ServiceProfileNotFound(
profile_id=profile_id)
def _populate_common_fields_in_dict(self, db_ref):
res = {'id': db_ref['id'],
'tenant_id': db_ref['tenant_id'],
'name': db_ref['name'],
'description': db_ref['description'],
'status': db_ref['status'],
'status_details': db_ref['status_details'],
'shared': db_ref.get('shared', False)}
return res
def _make_sc_node_dict(self, sc_node, fields=None):
res = {'id': sc_node['id'],
'tenant_id': sc_node['tenant_id'],
'name': sc_node['name'],
'description': sc_node['description'],
'service_profile_id': sc_node['service_profile_id'],
'service_type': sc_node['service_type'],
'config': sc_node['config'],
'shared': sc_node['shared']}
res = self._populate_common_fields_in_dict(sc_node)
res['service_profile_id'] = sc_node['service_profile_id']
res['service_type'] = sc_node['service_type']
res['config'] = sc_node['config']
res['servicechain_specs'] = [sc_spec['servicechain_spec_id']
for sc_spec in sc_node['specs']]
return self._fields(res, fields)
def _make_sc_spec_dict(self, spec, fields=None):
res = {'id': spec['id'],
'tenant_id': spec['tenant_id'],
'name': spec['name'],
'description': spec['description'],
'config_param_names': spec.get('config_param_names'),
'shared': spec['shared']}
res = self._populate_common_fields_in_dict(spec)
res['config_param_names'] = spec.get('config_param_names')
res['nodes'] = [sc_node['node_id'] for sc_node in spec['nodes']]
res['instances'] = [x['servicechain_instance_id'] for x in
spec['instances']]
@ -222,21 +220,19 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'provider_ptg_id': instance['provider_ptg_id'],
'consumer_ptg_id': instance['consumer_ptg_id'],
'management_ptg_id': instance['management_ptg_id'],
'classifier_id': instance['classifier_id']}
'classifier_id': instance['classifier_id'],
'status': instance['status'],
'status_details': instance['status_details']}
res['servicechain_specs'] = [sc_spec['servicechain_spec_id']
for sc_spec in instance['specs']]
return self._fields(res, fields)
def _make_service_profile_dict(self, profile, fields=None):
res = {'id': profile['id'],
'tenant_id': profile['tenant_id'],
'name': profile['name'],
'description': profile['description'],
'shared': profile['shared'],
'service_type': profile['service_type'],
'service_flavor': profile['service_flavor'],
'vendor': profile['vendor'],
'insertion_mode': profile['insertion_mode']}
res = self._populate_common_fields_in_dict(profile)
res['service_type'] = profile['service_type']
res['service_flavor'] = profile['service_flavor']
res['vendor'] = profile['vendor']
res['insertion_mode'] = profile['insertion_mode']
res['nodes'] = [node['id'] for node in profile['nodes']]
return self._fields(res, fields)
@ -253,9 +249,11 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
node_db = ServiceChainNode(
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
name=node['name'], description=node['description'],
service_profile_id=node['service_profile_id'],
service_type=node['service_type'],
config=node['config'], shared=node['shared'])
service_profile_id=node.get('service_profile_id'),
service_type=node.get('service_type'),
config=node['config'], shared=node['shared'],
status=node.get('status'),
status_details=node.get('status_details'))
context.session.add(node_db)
return self._make_sc_node_dict(node_db)
@ -419,7 +417,10 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
tenant_id=tenant_id,
name=spec['name'],
description=spec['description'],
shared=spec['shared'])
shared=spec['shared'],
status=spec.get('status'),
status_details=
spec.get('status_details'))
self._process_nodes_for_spec(context, spec_db, spec,
set_params=set_params)
context.session.add(spec_db)
@ -479,11 +480,11 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
instance = servicechain_instance['servicechain_instance']
tenant_id = self._get_tenant_id_for_create(context, instance)
with context.session.begin(subtransactions=True):
if not instance['management_ptg_id']:
if not instance.get('management_ptg_id'):
management_groups = (
self._grouppolicy_plugin.get_policy_target_groups(
context, {'service_management': [True],
'tenant_id': [instance['tenant_id']]}))
'tenant_id': [instance.get('tenant_id')]}))
if not management_groups:
# Fall back on shared service management
management_groups = (
@ -496,10 +497,12 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
tenant_id=tenant_id, name=instance['name'],
description=instance['description'],
config_param_values=instance['config_param_values'],
provider_ptg_id=instance['provider_ptg_id'],
consumer_ptg_id=instance['consumer_ptg_id'],
management_ptg_id=instance['management_ptg_id'],
classifier_id=instance['classifier_id'])
provider_ptg_id=instance.get('provider_ptg_id'),
consumer_ptg_id=instance.get('consumer_ptg_id'),
management_ptg_id=instance.get('management_ptg_id'),
classifier_id=instance.get('classifier_id'),
status=instance.get('status'),
status_details=instance.get('status_details'))
self._process_specs_for_instance(context, instance_db, instance)
context.session.add(instance_db)
return self._make_sc_instance_dict(instance_db)
@ -559,11 +562,13 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
profile_db = ServiceProfile(
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
name=profile['name'], description=profile['description'],
service_type=profile['service_type'],
insertion_mode=profile['insertion_mode'],
vendor=profile['vendor'],
service_flavor=profile['service_flavor'],
shared=profile['shared'])
service_type=profile.get('service_type'),
insertion_mode=profile.get('insertion_mode'),
vendor=profile.get('vendor'),
service_flavor=profile.get('service_flavor'),
shared=profile.get('shared'),
status=profile.get('status'),
status_details=profile.get('status_details'))
context.session.add(profile_db)
return self._make_service_profile_dict(profile_db)

View File

@ -407,6 +407,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'policy_target_group_id': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_or_none': None},
'required': True, 'is_visible': True},
@ -427,6 +431,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'policy_targets': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
@ -470,6 +478,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'policy_target_groups': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
@ -505,6 +517,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'ip_version': {'allow_post': True, 'allow_put': False,
'convert_to': attr.convert_to_int,
'validate': {'type:values': [4, 6]},
@ -544,6 +560,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'protocol': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': None,
'convert_to': convert_protocol},
@ -575,6 +595,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'action_type': {'allow_post': True, 'allow_put': False,
'convert_to': convert_action_to_case_insensitive,
'validate': {'type:values': gp_supported_actions},
@ -600,6 +624,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'enabled': {'allow_post': True, 'allow_put': True,
'default': True, 'convert_to': attr.convert_to_boolean,
'is_visible': True},
@ -631,6 +659,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'parent_id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
@ -661,6 +693,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'policy_target_groups': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
@ -687,6 +723,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'external_segments': {
'allow_post': True, 'allow_put': True, 'default': None,
'validate': {'type:uuid_list': None},
@ -719,6 +759,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'ip_version': {'allow_post': True, 'allow_put': False,
'convert_to': attr.convert_to_int,
'validate': {'type:values': [4, 6]},
@ -767,6 +811,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'ip_version': {'allow_post': True, 'allow_put': False,
'convert_to': attr.convert_to_int,
'validate': {'type:values': [4, 6]},

View File

@ -117,6 +117,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'service_type': {'allow_post': True, 'allow_put': False,
'validate': {'type:string_or_none': None},
'is_visible': True, 'default': None},
@ -144,6 +148,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'nodes': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
@ -170,6 +178,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'servicechain_specs': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
@ -208,6 +220,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
attr.SHARED: {'allow_post': True, 'allow_put': True,
'default': False, 'convert_to': attr.convert_to_boolean,
'is_visible': True, 'required_by_policy': True,

View File

@ -38,3 +38,9 @@ GP_NETWORK_SVC_PARAM_TYPE_STRING = 'string'
GP_NETWORK_SVC_PARAM_VALUE_SELF_SUBNET = 'self_subnet'
GP_NETWORK_SVC_PARAM_VALUE_NAT_POOL = 'nat_pool'
STATUS_ACTIVE = 'ACTIVE'
STATUS_BUILD = 'BUILD'
STATUS_ERROR = 'ERROR'
STATUS_STATES = [STATUS_ACTIVE, STATUS_BUILD, STATUS_ERROR]

View File

@ -21,21 +21,6 @@ class GroupPolicyContext(object):
self._plugin_context = plugin_context
class BaseResouceContext(GroupPolicyContext):
def __init__(self, plugin, plugin_context, resource, original=None):
super(BaseResouceContext, self).__init__(plugin, plugin_context)
self._resource = resource
self._original = original
@property
def current(self):
return self._resource
@property
def original(self):
return self._original
class PolicyTargetContext(GroupPolicyContext, api.PolicyTargetContext):
def __init__(self, plugin, plugin_context, policy_target,
@ -259,7 +244,21 @@ class PolicyRuleSetContext(GroupPolicyContext, api.PolicyRuleSetContext):
return self._original_policy_rule_set
class ExternalSegmentContext(BaseResouceContext, api.ExternalSegmentContext):
class ExternalSegmentContext(GroupPolicyContext, api.ExternalSegmentContext):
def __init__(self, plugin, plugin_context, external_segment,
original_external_segment=None):
super(ExternalSegmentContext, self).__init__(plugin, plugin_context)
self._external_segment = external_segment
self._original_external_segment = original_external_segment
@property
def current(self):
return self._external_segment
@property
def original(self):
return self._original_external_segment
def add_subnet(self, subnet_id):
self._plugin._set_subnet_to_es(self._plugin_context,
@ -267,7 +266,21 @@ class ExternalSegmentContext(BaseResouceContext, api.ExternalSegmentContext):
self.current['subnet_id'] = subnet_id
class ExternalPolicyContext(BaseResouceContext, api.ExternalPolicyContext):
class ExternalPolicyContext(GroupPolicyContext, api.ExternalPolicyContext):
def __init__(self, plugin, plugin_context, external_policy,
original_external_policy=None):
super(ExternalPolicyContext, self).__init__(plugin, plugin_context)
self._external_policy = external_policy
self._original_external_policy = original_external_policy
@property
def current(self):
return self._external_policy