Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # vim: tabstop=4 shiftwidth=4 softtabstop=4
- # Copyright 2012 Nicira Networks, Inc
- # All Rights Reserved.
- #
- # 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.
- '''Implement Security Groups Hanlder that proxies calles to Quantum
- The nova security_group_handler flag specifies which class is to be used
- to implement the security group calls.
- The NullSecurityGroupHandler provides a "no-op" plugin that is loaded
- by default and has no impact on current system behavior. In the future,
- special purposes classes that inherit from SecurityGroupHandlerBase
- will provide enhanced functionality and will be loadable via the
- security_group_handler flag.
- '''
- from nova import flags
- from nova import exception
- from nova.db import api as db
- from nova.db.sqlalchemy.session import get_session
- from nova.db.sqlalchemy import models
- from sqlalchemy.sql.expression import literal_column
- from nova.openstack.common import log as logging
- from nova.network import sg
- from nova.network import quantumv2
- from nova import quota
- from quantumclient.common import exceptions as q_exc
- FLAGS = flags.FLAGS
- QUOTAS = quota.QUOTAS
- LOG = logging.getLogger(__name__)
- class SecurityGroupHandlerQuantumProxy(sg.SecurityGroupHandlerBase):
- def __init__(self):
- LOG.info('Loading SecurityGroupHandlerQuantumProxy')
- def trigger_security_group_create_refresh(self, context, group):
- '''Called when a security group is created
- :param context: the security context.
- :param group: the new group added. group is a dictionary that contains
- the following: user_id, project_id, name, description).'''
- LOG.info('Creating security group: %s' % group)
- sg = db.security_group_get_by_name(context, group['project_id'],
- group['name'])
- body = {'security_group': {'external_id': sg.id,
- 'name': group['name'],
- 'description': group['description'],
- 'tenant_id': group['project_id']}}
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- try:
- quantum.create_security_group(body)
- except q_exc.QuantumClientException as e:
- LOG.error("Quuantum Error creating %s (%s)" % (group, e))
- # undo create
- if db.security_group_in_use(context, sg.id):
- msg = _("Security group is still in use")
- self.raise_invalid_group(msg)
- # Get reservations
- try:
- reservations = QUOTAS.reserve(context, security_groups=-1)
- except Exception:
- reservations = None
- LOG.error("Failed to update usages deallocating "
- "security group")
- LOG.warning(("Delete security group %s"), group['name'])
- db.security_group_destroy(context, sg.id)
- # Commit the reservations
- if reservations:
- QUOTAS.commit(context, reservations)
- # Raise exception here so user knows their operation failed.
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_security_group_destroy_refresh(self, context,
- security_group_id):
- '''Called when a security group is deleted
- :param context: the security context.
- :param security_group_id: the security group identifier.'''
- LOG.info('Deleting security group: %s' % security_group_id)
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- try:
- quantum.delete_security_group(security_group_id)
- except q_exc.QuantumClientException as e:
- LOG.error("quantum exception deleting security group (%s)" % e)
- # Undo delete
- # Could there be a race condition here where someone creates
- # another security group and we run out of quota?
- try:
- reservations = QUOTAS.reserve(context, security_groups=1)
- except exception.OverQuota:
- msg = _("Quota exceeded, too many security groups.")
- self.raise_over_quota(msg)
- LOG.warning(("Undeleting Security Group %s id"), security_group_id)
- session = get_session()
- with session.begin():
- session.query(models.SecurityGroup).\
- filter_by(id=security_group_id).\
- update({'deleted': False,
- 'deleted_at': None,
- 'updated_at': literal_column('updated_at')})
- session.query(models.SecurityGroupInstanceAssociation).\
- filter_by(security_group_id=security_group_id).\
- update({'deleted': False,
- 'deleted_at': None,
- 'updated_at': literal_column('updated_at')})
- session.query(models.SecurityGroupIngressRule).\
- filter_by(group_id=security_group_id).\
- update({'deleted': False,
- 'deleted_at': None,
- 'updated_at': literal_column('updated_at')})
- session.query(models.SecurityGroupIngressRule).\
- filter_by(parent_group_id=security_group_id).\
- update({'deleted': False,
- 'deleted_at': None,
- 'updated_at': literal_column('updated_at')})
- # Commit the reservation
- QUOTAS.commit(context, reservations)
- # Raise exception here so user knows their operation failed.
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_security_group_rule_create_refresh(self, context,
- rule_ids):
- '''Called when a rule is added to a security_group.
- :param context: the security context.
- :param rule_ids: a list of rule ids that have been affected.'''
- rules = []
- for rid in rule_ids:
- rules.append(db.security_group_rule_get(context, rid))
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- try:
- quantum.create_security_group_rule(
- body=self.mk_security_group_rule_dict(rules))
- except q_exc.QuantumClientException as e:
- LOG.exception("quantum exception deleting security group (%s)" % e)
- # Undo the createrule
- for rule_id in rule_ids:
- db.security_group_rule_destroy(context, rule_id)
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_security_group_rule_destroy_refresh(self, context,
- rule_ids):
- '''Called when a rule is removed from a security_group.
- :param context: the security context.
- :param rule_ids: a list of rule ids that have been affected.'''
- rules = []
- for rid in rule_ids:
- rules.append(db.security_group_rule_get(
- context.elevated(read_deleted='yes'), rid))
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- deleted_rids = set()
- try:
- for rid in rule_ids:
- quantum.delete_security_group_rule(rid)
- deleted_rids.add(rid)
- except q_exc.QuantumClientException as e:
- session = get_session()
- with session.begin():
- for rid in set(rule_ids) - deleted_rids:
- LOG.warning(("Undeleting Security Group Rule %s id"), rid)
- session.query(models.SecurityGroupIngressRule).\
- filter_by(id=rid).\
- update({'deleted': False,
- 'deleted_at': None,
- 'updated_at': literal_column('updated_at')})
- LOG.exception("quantum exception deleting security group (%s)" % e)
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_instance_add_security_group_refresh(self, context, instance,
- group_name):
- '''Called when a security group gains a new member.
- :param context: the security context.
- :param instance: the instance to be associated.
- :param group_name: the name of the security group to be associated.'''
- project_id = context.project_id
- security_group = db.security_group_get_by_name(context,
- project_id, group_name)
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- params = {'device_id': instance['uuid']}
- ports = quantum.list_ports(**params)
- for port in ports['ports']:
- if ('port_security' not in port or
- port['port_security'] != 'mac_ip'):
- LOG.warn("Cannot add security group %s to %s since no"
- "port_security mac_ip" % (group_name,
- instance['uuid']))
- # Cannot make any chance since port doesn't have port_security
- # enabled.
- continue
- updated_port = {'port': {'name': port['name'],
- 'admin_state_up': port['admin_state_up'],
- 'fixed_ips': port['fixed_ips'],
- 'device_id': port['device_id'],
- 'device_owner': port['device_owner']}}
- if 'security_groups' not in port:
- port['security_groups'] = []
- port['security_groups'].append(security_group.id)
- updated_port['port']['security_groups'] = port['security_groups']
- try:
- LOG.info("Adding security group %s %s to port %s" %
- (group_name, security_group.id, port['id']))
- quantum.update_port(port['id'], updated_port)
- except q_exc.QuantumClientException as e:
- # undo
- db.instance_remove_security_group(context.elevated(),
- instance['uuid'],
- security_group.id)
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_instance_remove_security_group_refresh(self, context, instance,
- group_name):
- '''Called when a security group loses a member.
- :param context: the security context.
- :param instance: the instance to be associated.
- :param group_name: the name of the security group to be associated.'''
- session = get_session()
- # get all the security groups associated with an instance
- with session.begin():
- sgs = session.query(models.SecurityGroupInstanceAssociation).\
- filter_by(instance_uuid=instance['uuid']).\
- filter_by(deleted=False).\
- all()
- security_group_ids = []
- for sg in sgs:
- security_group_ids.append(sg['security_group_id'])
- # This will cause us to get an admin token
- context.auth_token = None
- quantum = quantumv2.get_client(context)
- params = {'device_id': instance['uuid']}
- ports = quantum.list_ports(**params)
- for port in ports['ports']:
- if ('port_security' not in port or
- port['port_security'] != 'mac_ip'):
- # Cannot make any chance since port doesn't have port_security
- # enabled.
- LOG.warn("Cannot add security group %s to %s since no"
- "port_security mac_ip" % (group_name,
- instance['uuid']))
- continue
- updated_port = {'port': {'name': port['name'],
- 'admin_state_up': port['admin_state_up'],
- 'fixed_ips': port['fixed_ips'],
- 'device_id': port['device_id'],
- 'device_owner': port['device_owner'],
- 'security_groups': security_group_ids}}
- try:
- quantum.update_port(port['id'], updated_port)
- except q_exc.QuantumClientException as e:
- # undo
- security_group = db.security_group_get_by_name(
- context, context.project_id, group_name)
- db.instance_add_security_group(context.elevated(),
- instance['uuid'],
- security_group.id)
- raise q_exc.ConnectionFailed(reason=e)
- def trigger_security_group_members_refresh(self, context, group_ids):
- '''Called when a security group gains or loses a member.
- :param context: the security context.
- :param group_ids: a list of security group identifiers.'''
- pass
- #-----------------------------------------------------------------------------
- # Helper functions
- #-----------------------------------------------------------------------------
- def mk_security_group_rule_dict(self, security_group_rules):
- new_rules = []
- for rule in security_group_rules:
- proxy_rule = {'source_group_id': rule.group_id,
- 'source_ip_prefix': rule.cidr,
- 'external_id': rule.id,
- 'security_group_id': rule.parent_group_id,
- 'protocol': rule.protocol,
- 'direction': 'ingress'}
- if rule.protocol != 'icmp':
- proxy_rule['port_range_max'] = rule.to_port
- proxy_rule['port_range_min'] = rule.from_port
- new_rules.append(proxy_rule)
- return {'security_group_rules': new_rules}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement