|
@@ -19,21 +19,23 @@ from cloudbridge.cloud.base.resources import BaseNetwork
|
|
|
from cloudbridge.cloud.base.resources import BasePlacementZone
|
|
from cloudbridge.cloud.base.resources import BasePlacementZone
|
|
|
from cloudbridge.cloud.base.resources import BaseRegion
|
|
from cloudbridge.cloud.base.resources import BaseRegion
|
|
|
from cloudbridge.cloud.base.resources import BaseRouter
|
|
from cloudbridge.cloud.base.resources import BaseRouter
|
|
|
-from cloudbridge.cloud.base.resources import BaseSecurityGroup
|
|
|
|
|
-from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
|
|
|
|
|
from cloudbridge.cloud.base.resources import BaseSnapshot
|
|
from cloudbridge.cloud.base.resources import BaseSnapshot
|
|
|
from cloudbridge.cloud.base.resources import BaseSubnet
|
|
from cloudbridge.cloud.base.resources import BaseSubnet
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseVMFirewall
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseVMFirewallRule
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseVMFirewallRuleContainer
|
|
|
from cloudbridge.cloud.base.resources import BaseVMType
|
|
from cloudbridge.cloud.base.resources import BaseVMType
|
|
|
from cloudbridge.cloud.base.resources import BaseVolume
|
|
from cloudbridge.cloud.base.resources import BaseVolume
|
|
|
from cloudbridge.cloud.base.resources import ClientPagedResultList
|
|
from cloudbridge.cloud.base.resources import ClientPagedResultList
|
|
|
|
|
+from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
|
|
|
from cloudbridge.cloud.interfaces.resources import GatewayState
|
|
from cloudbridge.cloud.interfaces.resources import GatewayState
|
|
|
from cloudbridge.cloud.interfaces.resources import InstanceState
|
|
from cloudbridge.cloud.interfaces.resources import InstanceState
|
|
|
from cloudbridge.cloud.interfaces.resources import MachineImageState
|
|
from cloudbridge.cloud.interfaces.resources import MachineImageState
|
|
|
from cloudbridge.cloud.interfaces.resources import NetworkState
|
|
from cloudbridge.cloud.interfaces.resources import NetworkState
|
|
|
from cloudbridge.cloud.interfaces.resources import RouterState
|
|
from cloudbridge.cloud.interfaces.resources import RouterState
|
|
|
-from cloudbridge.cloud.interfaces.resources import SecurityGroup
|
|
|
|
|
from cloudbridge.cloud.interfaces.resources import SnapshotState
|
|
from cloudbridge.cloud.interfaces.resources import SnapshotState
|
|
|
from cloudbridge.cloud.interfaces.resources import SubnetState
|
|
from cloudbridge.cloud.interfaces.resources import SubnetState
|
|
|
|
|
+from cloudbridge.cloud.interfaces.resources import TrafficDirection
|
|
|
from cloudbridge.cloud.interfaces.resources import VolumeState
|
|
from cloudbridge.cloud.interfaces.resources import VolumeState
|
|
|
|
|
|
|
|
from .helpers import find_tag_value
|
|
from .helpers import find_tag_value
|
|
@@ -255,14 +257,14 @@ class AWSInstance(BaseInstance):
|
|
|
return self._ec2_instance.placement.get('AvailabilityZone')
|
|
return self._ec2_instance.placement.get('AvailabilityZone')
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def security_groups(self):
|
|
|
|
|
|
|
+ def vm_firewalls(self):
|
|
|
return [
|
|
return [
|
|
|
- self._provider.security.security_groups.get(group_id)
|
|
|
|
|
- for group_id in self.security_group_ids
|
|
|
|
|
|
|
+ self._provider.security.vm_firewalls.get(fw_id)
|
|
|
|
|
+ for fw_id in self.vm_firewall_ids
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def security_group_ids(self):
|
|
|
|
|
|
|
+ def vm_firewall_ids(self):
|
|
|
return list(set([
|
|
return list(set([
|
|
|
group.get('GroupId') for group in
|
|
group.get('GroupId') for group in
|
|
|
self._ec2_instance.security_groups
|
|
self._ec2_instance.security_groups
|
|
@@ -310,14 +312,14 @@ class AWSInstance(BaseInstance):
|
|
|
self._provider.ec2_conn.meta.client.disassociate_address(**params)
|
|
self._provider.ec2_conn.meta.client.disassociate_address(**params)
|
|
|
self.refresh()
|
|
self.refresh()
|
|
|
|
|
|
|
|
- def add_security_group(self, sg):
|
|
|
|
|
|
|
+ def add_vm_firewall(self, firewall):
|
|
|
self._ec2_instance.modify_attribute(
|
|
self._ec2_instance.modify_attribute(
|
|
|
- Groups=self.security_group_ids + [sg.id])
|
|
|
|
|
|
|
+ Groups=self.vm_firewall_ids + [firewall.id])
|
|
|
|
|
|
|
|
- def remove_security_group(self, sg):
|
|
|
|
|
|
|
+ def remove_vm_firewall(self, firewall):
|
|
|
self._ec2_instance.modify_attribute(
|
|
self._ec2_instance.modify_attribute(
|
|
|
- Groups=([sg_id for sg_id in self.security_group_ids
|
|
|
|
|
- if sg_id != sg.id]))
|
|
|
|
|
|
|
+ Groups=([fw_id for fw_id in self.vm_firewall_ids
|
|
|
|
|
+ if fw_id != firewall.id]))
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
@@ -544,74 +546,26 @@ class AWSKeyPair(BaseKeyPair):
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
-class AWSSecurityGroup(BaseSecurityGroup):
|
|
|
|
|
|
|
+class AWSVMFirewall(BaseVMFirewall):
|
|
|
|
|
|
|
|
- def __init__(self, provider, security_group):
|
|
|
|
|
- super(AWSSecurityGroup, self).__init__(provider, security_group)
|
|
|
|
|
|
|
+ def __init__(self, provider, _vm_firewall):
|
|
|
|
|
+ super(AWSVMFirewall, self).__init__(provider, _vm_firewall)
|
|
|
|
|
+ self._rule_container = AWSVMFirewallRuleContainer(provider, self)
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def name(self):
|
|
def name(self):
|
|
|
- return self._security_group.group_name
|
|
|
|
|
|
|
+ return self._vm_firewall.group_name
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def network_id(self):
|
|
def network_id(self):
|
|
|
- return self._security_group.vpc_id
|
|
|
|
|
|
|
+ return self._vm_firewall.vpc_id
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def rules(self):
|
|
def rules(self):
|
|
|
- return [AWSSecurityGroupRule(self._provider, r, self)
|
|
|
|
|
- for r in self._security_group.ip_permissions]
|
|
|
|
|
|
|
+ return self._rule_container
|
|
|
|
|
|
|
|
- def add_rule(self, ip_protocol=None, from_port=None, to_port=None,
|
|
|
|
|
- cidr_ip=None, src_group=None):
|
|
|
|
|
- try:
|
|
|
|
|
- src_group_id = (
|
|
|
|
|
- src_group.id if isinstance(src_group, SecurityGroup)
|
|
|
|
|
- else src_group)
|
|
|
|
|
-
|
|
|
|
|
- ip_perm_entry = {
|
|
|
|
|
- 'IpProtocol': ip_protocol,
|
|
|
|
|
- 'FromPort': from_port,
|
|
|
|
|
- 'ToPort': to_port,
|
|
|
|
|
- 'IpRanges': [{'CidrIp': cidr_ip}] if cidr_ip else None,
|
|
|
|
|
- 'UserIdGroupPairs': [{
|
|
|
|
|
- 'GroupId': src_group_id}
|
|
|
|
|
- ] if src_group_id else None
|
|
|
|
|
- }
|
|
|
|
|
- # Filter out empty values to please Boto
|
|
|
|
|
- ip_perms = [trim_empty_params(ip_perm_entry)]
|
|
|
|
|
- self._security_group.authorize_ingress(IpPermissions=ip_perms)
|
|
|
|
|
- self._security_group.reload()
|
|
|
|
|
- return self.get_rule(ip_protocol, from_port, to_port, cidr_ip,
|
|
|
|
|
- src_group_id)
|
|
|
|
|
- except ClientError as ec2e:
|
|
|
|
|
- if ec2e.response['Error']['Code'] == "InvalidPermission.Duplicate":
|
|
|
|
|
- return self.get_rule(ip_protocol, from_port, to_port, cidr_ip,
|
|
|
|
|
- src_group)
|
|
|
|
|
- else:
|
|
|
|
|
- raise ec2e
|
|
|
|
|
-
|
|
|
|
|
- def get_rule(self, ip_protocol=None, from_port=None, to_port=None,
|
|
|
|
|
- cidr_ip=None, src_group=None):
|
|
|
|
|
- src_group_id = (src_group.id if isinstance(src_group, SecurityGroup)
|
|
|
|
|
- else src_group)
|
|
|
|
|
- for rule in self._security_group.ip_permissions:
|
|
|
|
|
- if ip_protocol and rule['IpProtocol'] != ip_protocol:
|
|
|
|
|
- continue
|
|
|
|
|
- elif from_port and rule['FromPort'] != from_port:
|
|
|
|
|
- continue
|
|
|
|
|
- elif to_port and rule['ToPort'] != to_port:
|
|
|
|
|
- continue
|
|
|
|
|
- elif cidr_ip:
|
|
|
|
|
- if cidr_ip not in [x['CidrIp'] for x in rule['IpRanges']]:
|
|
|
|
|
- continue
|
|
|
|
|
- elif src_group_id:
|
|
|
|
|
- if src_group_id not in [
|
|
|
|
|
- group_pair.get('GroupId') for group_pair in
|
|
|
|
|
- rule.get('UserIdGroupPairs', [])]:
|
|
|
|
|
- continue
|
|
|
|
|
- return AWSSecurityGroupRule(self._provider, rule, self)
|
|
|
|
|
- return None
|
|
|
|
|
|
|
+ def refresh(self):
|
|
|
|
|
+ self._vm_firewall.reload()
|
|
|
|
|
|
|
|
def to_json(self):
|
|
def to_json(self):
|
|
|
attr = inspect.getmembers(self, lambda a: not inspect.isroutine(a))
|
|
attr = inspect.getmembers(self, lambda a: not inspect.isroutine(a))
|
|
@@ -623,77 +577,137 @@ class AWSSecurityGroup(BaseSecurityGroup):
|
|
|
return js
|
|
return js
|
|
|
|
|
|
|
|
|
|
|
|
|
-class AWSSecurityGroupRule(BaseSecurityGroupRule):
|
|
|
|
|
|
|
+class AWSVMFirewallRuleContainer(BaseVMFirewallRuleContainer):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, firewall):
|
|
|
|
|
+ super(AWSVMFirewallRuleContainer, self).__init__(provider, firewall)
|
|
|
|
|
+
|
|
|
|
|
+ def list(self, limit=None, marker=None):
|
|
|
|
|
+ # pylint:disable=protected-access
|
|
|
|
|
+ rules = [AWSVMFirewallRule(self.firewall,
|
|
|
|
|
+ TrafficDirection.INBOUND, r)
|
|
|
|
|
+ for r in self.firewall._vm_firewall.ip_permissions]
|
|
|
|
|
+ rules = rules + [
|
|
|
|
|
+ AWSVMFirewallRule(
|
|
|
|
|
+ self.firewall, TrafficDirection.OUTBOUND, r)
|
|
|
|
|
+ for r in self.firewall._vm_firewall.ip_permissions_egress]
|
|
|
|
|
+ return ClientPagedResultList(self._provider, rules,
|
|
|
|
|
+ limit=limit, marker=marker)
|
|
|
|
|
+
|
|
|
|
|
+ def create(self, direction, protocol=None, from_port=None,
|
|
|
|
|
+ to_port=None, cidr=None, src_dest_fw=None):
|
|
|
|
|
+ src_dest_fw_id = (
|
|
|
|
|
+ src_dest_fw.id if isinstance(src_dest_fw, AWSVMFirewall)
|
|
|
|
|
+ else src_dest_fw)
|
|
|
|
|
+
|
|
|
|
|
+ ip_perm_entry = AWSVMFirewallRule._construct_ip_perms(
|
|
|
|
|
+ protocol, from_port, to_port, cidr, src_dest_fw_id)
|
|
|
|
|
+ # Filter out empty values to please Boto
|
|
|
|
|
+ ip_perms = [trim_empty_params(ip_perm_entry)]
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ if direction == TrafficDirection.INBOUND:
|
|
|
|
|
+ # pylint:disable=protected-access
|
|
|
|
|
+ self.firewall._vm_firewall.authorize_ingress(
|
|
|
|
|
+ IpPermissions=ip_perms)
|
|
|
|
|
+ elif direction == TrafficDirection.OUTBOUND:
|
|
|
|
|
+ # pylint:disable=protected-access
|
|
|
|
|
+ self.firewall._vm_firewall.authorize_egress(
|
|
|
|
|
+ IpPermissions=ip_perms)
|
|
|
|
|
+ else:
|
|
|
|
|
+ raise InvalidValueException("direction", direction)
|
|
|
|
|
+ self.firewall.refresh()
|
|
|
|
|
+ return AWSVMFirewallRule(self.firewall, direction, ip_perm_entry)
|
|
|
|
|
+ except ClientError as ec2e:
|
|
|
|
|
+ if ec2e.response['Error']['Code'] == "InvalidPermission.Duplicate":
|
|
|
|
|
+ return AWSVMFirewallRule(
|
|
|
|
|
+ self.firewall, direction, ip_perm_entry)
|
|
|
|
|
+ else:
|
|
|
|
|
+ raise ec2e
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class AWSVMFirewallRule(BaseVMFirewallRule):
|
|
|
|
|
|
|
|
- def __init__(self, provider, rule, parent):
|
|
|
|
|
- super(AWSSecurityGroupRule, self).__init__(provider, rule, parent)
|
|
|
|
|
|
|
+ def __init__(self, parent_fw, direction, rule):
|
|
|
|
|
+ self._direction = direction
|
|
|
|
|
+ super(AWSVMFirewallRule, self).__init__(parent_fw, rule)
|
|
|
|
|
+
|
|
|
|
|
+ # cache id
|
|
|
|
|
+ md5 = hashlib.md5()
|
|
|
|
|
+ md5.update(self._name.encode('ascii'))
|
|
|
|
|
+ self._id = md5.hexdigest()
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def id(self):
|
|
def id(self):
|
|
|
- md5 = hashlib.md5()
|
|
|
|
|
- md5.update("{0}-{1}-{2}-{3}".format(
|
|
|
|
|
- self.ip_protocol, self.from_port, self.to_port, self.cidr_ip)
|
|
|
|
|
- .encode('ascii'))
|
|
|
|
|
- return md5.hexdigest()
|
|
|
|
|
|
|
+ return self._id
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def direction(self):
|
|
|
|
|
+ return self._direction
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def ip_protocol(self):
|
|
|
|
|
|
|
+ def protocol(self):
|
|
|
return self._rule.get('IpProtocol')
|
|
return self._rule.get('IpProtocol')
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def from_port(self):
|
|
def from_port(self):
|
|
|
- return self._rule.get('FromPort', 0)
|
|
|
|
|
|
|
+ return self._rule.get('FromPort')
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def to_port(self):
|
|
def to_port(self):
|
|
|
- return self._rule.get('ToPort', 0)
|
|
|
|
|
|
|
+ return self._rule.get('ToPort')
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def cidr_ip(self):
|
|
|
|
|
- if len(self._rule.get('IpRanges', [])) > 0:
|
|
|
|
|
|
|
+ def cidr(self):
|
|
|
|
|
+ if len(self._rule.get('IpRanges') or []) > 0:
|
|
|
return self._rule['IpRanges'][0].get('CidrIp')
|
|
return self._rule['IpRanges'][0].get('CidrIp')
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def group_id(self):
|
|
|
|
|
- if len(self._rule['UserIdGroupPairs']) > 0:
|
|
|
|
|
|
|
+ def src_dest_fw_id(self):
|
|
|
|
|
+ if len(self._rule.get('UserIdGroupPairs') or []) > 0:
|
|
|
return self._rule['UserIdGroupPairs'][0]['GroupId']
|
|
return self._rule['UserIdGroupPairs'][0]['GroupId']
|
|
|
else:
|
|
else:
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def group(self):
|
|
|
|
|
- if self.group_id:
|
|
|
|
|
- return AWSSecurityGroup(
|
|
|
|
|
|
|
+ def src_dest_fw(self):
|
|
|
|
|
+ if self.src_dest_fw_id:
|
|
|
|
|
+ return AWSVMFirewall(
|
|
|
self._provider,
|
|
self._provider,
|
|
|
- self._provider.ec2_conn.SecurityGroup(self.group_id))
|
|
|
|
|
|
|
+ self._provider.ec2_conn.SecurityGroup(self.src_dest_fw_id))
|
|
|
else:
|
|
else:
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
- def to_json(self):
|
|
|
|
|
- attr = inspect.getmembers(self, lambda a: not (inspect.isroutine(a)))
|
|
|
|
|
- js = {k: v for (k, v) in attr if not k.startswith('_')}
|
|
|
|
|
- js['group'] = self.group.id if self.group else ''
|
|
|
|
|
- js['parent'] = self.parent.id if self.parent else ''
|
|
|
|
|
- return js
|
|
|
|
|
-
|
|
|
|
|
- def delete(self):
|
|
|
|
|
-
|
|
|
|
|
- ip_perm_entry = {
|
|
|
|
|
- 'IpProtocol': self.ip_protocol,
|
|
|
|
|
- 'FromPort': self.from_port,
|
|
|
|
|
- 'ToPort': self.to_port,
|
|
|
|
|
- 'IpRanges': [{'CidrIp': self.cidr_ip}] if self.cidr_ip else None,
|
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def _construct_ip_perms(protocol, from_port, to_port, cidr,
|
|
|
|
|
+ src_dest_fw_id):
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'IpProtocol': protocol,
|
|
|
|
|
+ 'FromPort': from_port,
|
|
|
|
|
+ 'ToPort': to_port,
|
|
|
|
|
+ 'IpRanges': [{'CidrIp': cidr}] if cidr else None,
|
|
|
'UserIdGroupPairs': [{
|
|
'UserIdGroupPairs': [{
|
|
|
- 'GroupId': self.group_id}
|
|
|
|
|
- ] if self.group_id else None
|
|
|
|
|
|
|
+ 'GroupId': src_dest_fw_id}
|
|
|
|
|
+ ] if src_dest_fw_id else None
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ def delete(self):
|
|
|
|
|
+ ip_perm_entry = self._construct_ip_perms(
|
|
|
|
|
+ self.protocol, self.from_port, self.to_port,
|
|
|
|
|
+ self.cidr, self.src_dest_fw_id)
|
|
|
|
|
+
|
|
|
# Filter out empty values to please Boto
|
|
# Filter out empty values to please Boto
|
|
|
ip_perms = [trim_empty_params(ip_perm_entry)]
|
|
ip_perms = [trim_empty_params(ip_perm_entry)]
|
|
|
|
|
|
|
|
- self.parent._security_group.revoke_ingress(IpPermissions=ip_perms)
|
|
|
|
|
- self.parent._security_group.reload()
|
|
|
|
|
|
|
+ # pylint:disable=protected-access
|
|
|
|
|
+ if self.direction == TrafficDirection.INBOUND:
|
|
|
|
|
+ self.firewall._vm_firewall.revoke_ingress(
|
|
|
|
|
+ IpPermissions=ip_perms)
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.firewall._vm_firewall.revoke_egress(
|
|
|
|
|
+ IpPermissions=ip_perms)
|
|
|
|
|
+ self.firewall.refresh()
|
|
|
|
|
|
|
|
|
|
|
|
|
class AWSBucketObject(BaseBucketObject):
|
|
class AWSBucketObject(BaseBucketObject):
|