summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorTodd Willey <todd@ansolabs.com>2011-01-17 23:18:46 -0500
committerTodd Willey <todd@ansolabs.com>2011-01-17 23:18:46 -0500
commitd4e7eb818c9f4ec51fd3a88a0e92d557867511d4 (patch)
treed89f9972cbf283a77d6e6bca3fb202c42a01ec04 /nova
parent3403e773f5a38c5d415e4ab66799c6e239223a0d (diff)
Add rules to database, cast refresh message and trickle down to firewall driver.
Diffstat (limited to 'nova')
-rw-r--r--nova/api/ec2/admin.py43
-rw-r--r--nova/compute/api.py9
-rw-r--r--nova/compute/manager.py5
-rw-r--r--nova/db/api.py8
-rw-r--r--nova/db/sqlalchemy/api.py12
-rw-r--r--nova/db/sqlalchemy/models.py11
-rw-r--r--nova/virt/connection.py1
-rw-r--r--nova/virt/libvirt_conn.py10
8 files changed, 95 insertions, 4 deletions
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index b784c5a00..1ae5f7094 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -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'}
diff --git a/nova/compute/api.py b/nova/compute/api.py
index a6b99c1cb..607a9ef25 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -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.
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 6f09ce674..9c4a23d08 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -170,6 +170,11 @@ class ComputeManager(manager.Manager):
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."""
context = context.elevated()
diff --git a/nova/db/api.py b/nova/db/api.py
index f9d561587..a05c8159e 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -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)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index b63b84bed..4223aa0f7 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -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:
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index bf5e48b04..1d82cff18 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -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'
diff --git a/nova/virt/connection.py b/nova/virt/connection.py
index 13181b730..f5a978997 100644
--- a/nova/virt/connection.py
+++ b/nova/virt/connection.py
@@ -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
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index f38af5ed8..fa5dc502e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -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):
"""