Add rules to database, cast refresh message and trickle down to firewall driver.

This commit is contained in:
Todd Willey
2011-01-17 23:18:46 -05:00
parent 3403e773f5
commit d4e7eb818c
8 changed files with 95 additions and 4 deletions

View File

@@ -21,7 +21,10 @@ Admin API controller, exposed through http via the api worker.
"""
import base64
import IPy
import urllib
from nova import compute
from nova import db
from nova import exception
from nova import log as logging
@@ -70,6 +73,9 @@ class AdminController(object):
def __str__(self):
return 'AdminController'
def __init__(self):
self.compute_api = compute.API()
def describe_user(self, _context, name, **_kwargs):
"""Returns user data, including access and secret keys."""
return user_dict(manager.AuthManager().get_user(name))
@@ -210,10 +216,39 @@ class AdminController(object):
"""Returns status info for single node."""
return host_dict(db.host_get(name))
def _provider_fw_rule_exists(context, rule):
for old_rule in db.provider_fw_rule_get_all(context):
for key in ('cidr', 'from_port', 'to_port', 'protocol'):
dupe = True
if rule[key] != old_rule[key]:
dupe = False
if dupe:
return dupe
return False
def block_external_addresses(self, context, cidr):
"""Add provider-level firewall rules to block incoming traffic."""
LOG.audit(_("Blocking access to all projects incoming from %s"),
LOG.audit(_("Blocking traffic to all projects incoming from %s"),
cidr, context=context)
raise NotImplementedError(_("Awaiting implementation."))
# TODO(todd): implement
# return {'status': 'OK', 'message': 'Disabled (number) IPs'}
rule = {'cidr': IPy.IP(urllib.unquote(cidr).decode())}
tcp_rule = rule.copy()
tcp_rule.update({"protocol": "TCP", "from_port": 1, "to_port": 65535})
udp_rule = rule.copy()
udp_rule.update({"protocol": "UDP", "from_port": 1, "to_port": 65535})
icmp_rule = rule.copy()
icmp_rule.update({"protocol": "ICMP", "from_port": -1, "to_port": -1})
rules_added = 0
if not self._provider_fw_rule_exists(context, tcp_rule):
db.provider_fw_rule_create(context, tcp_rule)
rules_added += 1
if not self._provider_fw_rule_exists(context, udp_rule):
db.provider_fw_rule_create(context, udp_rule)
rules_added += 1
if not self._provider_fw_rule_exists(context, icmp_rule):
db.provider_fw_rule_create(context, icmp_rule)
rules_added += 1
if rules_added == 0:
raise exception.ApiError(_('Duplicate rule'))
self.compute_api.trigger_provider_fw_rules_refresh(context)
return {'status': 'OK', 'message': 'Disabled (number) IPs'}

View File

@@ -268,6 +268,15 @@ class API(base.Base):
{"method": "refresh_security_group_members",
"args": {"security_group_id": group_id}})
def trigger_provider_fw_rules_refresh(self, context):
"""Called when a rule is added to or removed from a security_group"""
hosts = [x['host'] for x in db.service_get_all_compute_sorted(context)]
for host in hosts:
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "refresh_provider_fw_rules", "args": {}})
def update(self, context, instance_id, **kwargs):
"""Updates the instance in the datastore.

View File

@@ -169,6 +169,11 @@ class ComputeManager(manager.Manager):
"""This call passes straight through to the virtualization driver."""
return self.driver.refresh_security_group_members(security_group_id)
@exception.wrap_exception
def refresh_provider_fw_rules(self, context, **_kwargs):
"""This call passes straight through to the virtualization driver."""
return self.driver.refresh_security_group_rules()
@exception.wrap_exception
def run_instance(self, context, instance_id, **_kwargs):
"""Launch a new instance with specified options."""

View File

@@ -813,6 +813,14 @@ def security_group_rule_destroy(context, security_group_rule_id):
###################
def provider_fw_rule_create(context, rule):
"""Add a firewall rule at the provider level (all hosts & instances)."""
return IMPL.provider_fw_rule_create(context, rule)
###################
def user_get(context, id):
"""Get user by id."""
return IMPL.user_get(context, id)

View File

@@ -1687,6 +1687,18 @@ def security_group_rule_destroy(context, security_group_rule_id):
###################
@require_admin_context
def provider_fw_rule_create(context, rule):
fw_rule_ref = models.ProviderFirewallRule()
fw_rule_ref.update(rule)
fw_rule_ref.save()
return fw_rule_ref
###################
@require_admin_context
def user_get(context, id, session=None):
if not session:

View File

@@ -394,6 +394,17 @@ class SecurityGroupIngressRule(BASE, NovaBase):
group_id = Column(Integer, ForeignKey('security_groups.id'))
class ProviderFirewallRule(BASE, NovaBase):
"""Represents a rule in a security group."""
__tablename__ = 'provider_fw_rules'
id = Column(Integer, primary_key=True)
protocol = Column(String(5)) # "tcp", "udp", or "icmp"
from_port = Column(Integer)
to_port = Column(Integer)
cidr = Column(String(255))
class KeyPair(BASE, NovaBase):
"""Represents a public key pair for ssh."""
__tablename__ = 'key_pairs'

View File

@@ -54,6 +54,7 @@ def get_connection(read_only=False):
* fake
* libvirt
* xenapi
* hyperv
"""
# TODO(termie): maybe lazy load after initial check for permissions
# TODO(termie): check whether we can be disconnected

View File

@@ -848,6 +848,9 @@ class LibvirtConnection(object):
def refresh_security_group_members(self, security_group_id):
self.firewall_driver.refresh_security_group_members(security_group_id)
def refresh_provier_fw_rules(self):
self.firewall_driver.refresh_provider_fw_rules()
class FirewallDriver(object):
def prepare_instance_filter(self, instance):
@@ -884,6 +887,13 @@ class FirewallDriver(object):
the security group."""
raise NotImplementedError()
def refresh_provider_fw_rules(self):
"""Refresh common rules for all hosts/instances from data store.
Gets called when a rule has been added to or removed from
the list of rules (via admin api)."""
raise NotImplementedError()
class NWFilterFirewall(FirewallDriver):
"""