531
523
notfound = exception.SecurityGroupNotFound
532
524
if not source_security_group:
533
525
raise notfound(security_group_id=source_security_group_name)
534
values['group_id'] = source_security_group['id']
536
# If this fails, it throws an exception. This is what we want.
537
cidr_ip = urllib.unquote(cidr_ip).decode()
539
if not utils.is_valid_cidr(cidr_ip):
540
# Raise exception for non-valid address
541
raise exception.EC2APIError(_("Invalid CIDR"))
543
values['cidr'] = cidr_ip
545
values['cidr'] = '0.0.0.0/0'
547
if source_security_group_name:
548
# Open everything if an explicit port range or type/code are not
549
# specified, but only if a source group was specified.
550
ip_proto_upper = ip_protocol.upper() if ip_protocol else ''
551
if (ip_proto_upper == 'ICMP' and
552
from_port is None and to_port is None):
555
elif (ip_proto_upper in ['TCP', 'UDP'] and from_port is None
556
and to_port is None):
560
if ip_protocol and from_port is not None and to_port is not None:
562
ip_protocol = str(ip_protocol)
564
# Verify integer conversions
565
from_port = int(from_port)
566
to_port = int(to_port)
568
if ip_protocol.upper() == 'ICMP':
569
raise exception.InvalidInput(reason="Type and"
570
" Code must be integers for ICMP protocol type")
572
raise exception.InvalidInput(reason="To and From ports "
575
if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
576
raise exception.InvalidIpProtocol(protocol=ip_protocol)
578
# Verify that from_port must always be less than
579
# or equal to to_port
580
if (ip_protocol.upper() in ['TCP', 'UDP'] and
581
(from_port > to_port)):
582
raise exception.InvalidPortRange(from_port=from_port,
583
to_port=to_port, msg="Former value cannot"
584
" be greater than the later")
586
# Verify valid TCP, UDP port ranges
587
if (ip_protocol.upper() in ['TCP', 'UDP'] and
588
(from_port < 1 or to_port > 65535)):
589
raise exception.InvalidPortRange(from_port=from_port,
590
to_port=to_port, msg="Valid TCP ports should"
591
" be between 1-65535")
593
# Verify ICMP type and code
594
if (ip_protocol.upper() == "ICMP" and
595
(from_port < -1 or from_port > 255 or
596
to_port < -1 or to_port > 255)):
597
raise exception.InvalidPortRange(from_port=from_port,
598
to_port=to_port, msg="For ICMP, the"
599
" type:code must be valid")
601
values['protocol'] = ip_protocol
602
values['from_port'] = from_port
603
values['to_port'] = to_port
605
# If cidr based filtering, protocol and ports are mandatory
611
def _security_group_rule_exists(self, security_group, values):
612
"""Indicates whether the specified rule values are already
613
defined in the given security group.
615
for rule in security_group.rules:
617
keys = ('group_id', 'cidr', 'from_port', 'to_port', 'protocol')
619
if rule.get(key) != values.get(key):
526
group_id = source_security_group['id']
527
return self.security_group_api.new_group_ingress_rule(
528
group_id, ip_protocol, from_port, to_port)
530
cidr = self.security_group_api.parse_cidr(cidr_ip)
531
return self.security_group_api.new_cidr_ingress_rule(
532
cidr, ip_protocol, from_port, to_port)
534
def _validate_group_identifier(self, group_name, group_id):
535
if not group_name and not group_id:
536
err = _("Not enough parameters, need group_name or group_id")
537
raise exception.EC2APIError(err)
539
def _validate_rulevalues(self, rulesvalues):
541
err = _("%s Not enough parameters to build a valid rule")
542
raise exception.EC2APIError(err % rulesvalues)
626
544
def revoke_security_group_ingress(self, context, group_name=None,
627
545
group_id=None, **kwargs):
628
if not group_name and not group_id:
629
err = _("Not enough parameters, need group_name or group_id")
630
raise exception.EC2APIError(err)
631
self.compute_api.ensure_default_security_group(context)
632
notfound = exception.SecurityGroupNotFound
634
security_group = db.security_group_get_by_name(context,
637
if not security_group:
638
raise notfound(security_group_id=group_name)
640
security_group = db.security_group_get(context, group_id)
641
if not security_group:
642
raise notfound(security_group_id=group_id)
644
msg = _("Revoke security group ingress %s")
645
LOG.audit(msg, security_group['name'], context=context)
648
prevalues = kwargs['ip_permissions']
650
prevalues.append(kwargs)
546
self._validate_group_identifier(group_name, group_id)
548
security_group = self.security_group_api.get(context, group_name,
551
prevalues = kwargs.get('ip_permissions', [kwargs])
653
554
for values in prevalues:
654
555
rulesvalues = self._rule_args_to_dict(context, values)
656
err = _("%s Not enough parameters to build a valid rule")
657
raise exception.EC2APIError(err % rulesvalues)
556
self._validate_rulevalues(rulesvalues)
659
557
for values_for_rule in rulesvalues:
660
558
values_for_rule['parent_group_id'] = security_group.id
661
rule_id = self._security_group_rule_exists(security_group,
664
db.security_group_rule_destroy(context, rule_id)
665
rule_ids.append(rule_id)
667
# NOTE(vish): we removed a rule, so refresh
668
self.compute_api.trigger_security_group_rules_refresh(
670
security_group_id=security_group['id'])
671
self.sgh.trigger_security_group_rule_destroy_refresh(
560
rule_ids.append(self.security_group_api.rule_exists(
561
security_group, values_for_rule))
563
rule_ids = [id for id in rule_ids if id]
566
self.security_group_api.remove_rules(context, security_group,
674
571
raise exception.EC2APIError(_("No rule for the specified parameters."))
676
573
# TODO(soren): This has only been tested with Boto as the client.
680
577
def authorize_security_group_ingress(self, context, group_name=None,
681
578
group_id=None, **kwargs):
682
if not group_name and not group_id:
683
err = _("Not enough parameters, need group_name or group_id")
684
raise exception.EC2APIError(err)
685
self.compute_api.ensure_default_security_group(context)
686
notfound = exception.SecurityGroupNotFound
688
security_group = db.security_group_get_by_name(context,
691
if not security_group:
692
raise notfound(security_group_id=group_name)
694
security_group = db.security_group_get(context, group_id)
695
if not security_group:
696
raise notfound(security_group_id=group_id)
698
msg = _("Authorize security group ingress %s")
699
LOG.audit(msg, security_group['name'], context=context)
702
prevalues = kwargs['ip_permissions']
704
prevalues.append(kwargs)
579
self._validate_group_identifier(group_name, group_id)
581
security_group = self.security_group_api.get(context, group_name,
584
prevalues = kwargs.get('ip_permissions', [kwargs])
706
586
for values in prevalues:
707
587
rulesvalues = self._rule_args_to_dict(context, values)
709
err = _("%s Not enough parameters to build a valid rule")
710
raise exception.EC2APIError(err % rulesvalues)
588
self._validate_rulevalues(rulesvalues)
711
589
for values_for_rule in rulesvalues:
712
590
values_for_rule['parent_group_id'] = security_group.id
713
if self._security_group_rule_exists(security_group,
591
if self.security_group_api.rule_exists(security_group,
715
593
err = _('%s - This rule already exists in group')
716
594
raise exception.EC2APIError(err % values_for_rule)
717
595
postvalues.append(values_for_rule)
719
count = QUOTAS.count(context, 'security_group_rules',
720
security_group['id'])
722
QUOTAS.limit_check(context, security_group_rules=count + 1)
723
except exception.OverQuota:
724
msg = _("Quota exceeded, too many security group rules.")
725
raise exception.EC2APIError(msg)
728
for values_for_rule in postvalues:
729
security_group_rule = db.security_group_rule_create(
732
rule_ids.append(security_group_rule['id'])
735
self.compute_api.trigger_security_group_rules_refresh(
737
security_group_id=security_group['id'])
738
self.sgh.trigger_security_group_rule_create_refresh(
598
self.security_group_api.add_rules(context, security_group['id'],
599
security_group['name'], postvalues)
742
602
raise exception.EC2APIError(_("No rule for the specified parameters."))
759
619
return source_project_id
761
621
def create_security_group(self, context, group_name, group_description):
762
if not re.match('^[a-zA-Z0-9_\- ]+$', str(group_name)):
763
# Some validation to ensure that values match API spec.
764
# - Alphanumeric characters, spaces, dashes, and underscores.
765
# TODO(Daviey): LP: #813685 extend beyond group_name checking, and
766
# probably create a param validator that can be used elsewhere.
767
err = _("Value (%s) for parameter GroupName is invalid."
768
" Content limited to Alphanumeric characters, "
769
"spaces, dashes, and underscores.") % group_name
770
# err not that of master ec2 implementation, as they fail to raise.
771
raise exception.InvalidParameterValue(err=err)
773
if len(str(group_name)) > 255:
774
err = _("Value (%s) for parameter GroupName is invalid."
775
" Length exceeds maximum of 255.") % group_name
776
raise exception.InvalidParameterValue(err=err)
778
LOG.audit(_("Create Security Group %s"), group_name, context=context)
779
self.compute_api.ensure_default_security_group(context)
780
if db.security_group_exists(context, context.project_id, group_name):
781
msg = _('group %s already exists')
782
raise exception.EC2APIError(msg % group_name)
785
reservations = QUOTAS.reserve(context, security_groups=1)
786
except exception.OverQuota:
787
msg = _("Quota exceeded, too many security groups.")
788
raise exception.EC2APIError(msg)
791
group = {'user_id': context.user_id,
792
'project_id': context.project_id,
794
'description': group_description}
795
group_ref = db.security_group_create(context, group)
797
self.sgh.trigger_security_group_create_refresh(context, group)
799
# Commit the reservation
800
QUOTAS.commit(context, reservations)
802
with excutils.save_and_reraise_exception():
803
QUOTAS.rollback(context, reservations)
622
if isinstance(group_name, unicode):
623
group_name = group_name.encode('utf-8')
624
if FLAGS.ec2_strict_validation:
625
# EC2 specification gives constraints for name and description:
626
# Accepts alphanumeric characters, spaces, dashes, and underscores
627
allowed = '^[a-zA-Z0-9_\- ]+$'
628
self.security_group_api.validate_property(group_name, 'name',
630
self.security_group_api.validate_property(group_description,
631
'description', allowed)
633
# Amazon accepts more symbols.
634
# So, allow POSIX [:print:] characters.
635
allowed = r'^[\x20-\x7E]+$'
636
self.security_group_api.validate_property(group_name, 'name',
639
group_ref = self.security_group_api.create(context, group_name,
805
642
return {'securityGroupSet': [self._format_security_group(context,
810
647
if not group_name and not group_id:
811
648
err = _("Not enough parameters, need group_name or group_id")
812
649
raise exception.EC2APIError(err)
813
notfound = exception.SecurityGroupNotFound
815
security_group = db.security_group_get_by_name(context,
818
if not security_group:
819
raise notfound(security_group_id=group_name)
821
security_group = db.security_group_get(context, group_id)
822
if not security_group:
823
raise notfound(security_group_id=group_id)
824
if db.security_group_in_use(context, security_group.id):
825
raise exception.InvalidGroup(reason="In Use")
829
reservations = QUOTAS.reserve(context, security_groups=-1)
832
LOG.exception(_("Failed to update usages deallocating "
835
LOG.audit(_("Delete security group %s"), group_name, context=context)
836
db.security_group_destroy(context, security_group.id)
838
self.sgh.trigger_security_group_destroy_refresh(context,
841
# Commit the reservations
843
QUOTAS.commit(context, reservations)
651
security_group = self.security_group_api.get(context, group_name,
654
self.security_group_api.destroy(context, security_group)
1301
1112
" instance %(instance_id)s") % locals(), context=context)
1302
1113
instance_id = ec2utils.ec2_id_to_id(instance_id)
1303
1114
instance = self.compute_api.get(context, instance_id)
1116
cached_ipinfo = ec2utils.get_ip_info_for_instance(context, instance)
1117
fixed_ips = cached_ipinfo['fixed_ips'] + cached_ipinfo['fixed_ip6s']
1119
msg = _('Unable to associate IP Address, no fixed_ips.')
1120
raise exception.EC2APIError(msg)
1122
# TODO(tr3buchet): this will associate the floating IP with the
1123
# first fixed_ip an instance has. This should be
1124
# changed to support specifying a particular fixed_ip if
1125
# multiple exist but this may not apply to ec2..
1126
if len(fixed_ips) > 1:
1127
msg = _('multiple fixed_ips exist, using the first: %s')
1128
LOG.warning(msg, fixed_ips[0])
1305
self.compute_api.associate_floating_ip(context,
1308
return {'return': "true"}
1309
except exception.FloatingIpNotFound:
1310
raise exception.EC2APIError(_('Unable to associate IP Address.'))
1131
self.network_api.associate_floating_ip(context, instance,
1132
floating_address=public_ip,
1133
fixed_address=fixed_ips[0])
1134
return {'return': 'true'}
1135
except exception.FloatingIpAssociated:
1136
msg = _('Floating ip is already associated.')
1137
raise exception.EC2APIError(msg)
1138
except exception.NoFloatingIpInterface:
1139
msg = _('l3driver call to add floating ip failed.')
1140
raise exception.EC2APIError(msg)
1142
msg = _('Error, unable to associate floating ip.')
1144
raise exception.EC2APIError(msg)
1312
1146
def disassociate_address(self, context, public_ip, **kwargs):
1147
instance_id = self.network_api.get_instance_id_by_floating_address(
1149
instance = self.compute_api.get(context, instance_id)
1313
1150
LOG.audit(_("Disassociate address %s"), public_ip, context=context)
1314
self.network_api.disassociate_floating_ip(context, address=public_ip)
1152
self.network_api.disassociate_floating_ip(context, instance,
1154
except exception.FloatingIpNotAssociated:
1155
msg = _('Floating ip is not associated.')
1156
raise exception.EC2APIError(msg)
1315
1158
return {'return': "true"}
1317
1160
def run_instances(self, context, **kwargs):