Example #1
0
    def __init__(self, message=None, **kwargs):
        self.kwargs = kwargs

        if not message:
            try:
                message = self.msg_fmt % kwargs
            except Exception:
                exc_info = sys.exc_info()
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_("Exception in string format operation for " "%s exception"), self.__class__.__name__)
                for name, value in kwargs.iteritems():
                    LOG.error("%s: %s" % (name, value))

                if CONF.fatal_exception_format_errors:
                    raise exc_info[0], exc_info[1], exc_info[2]
                else:
                    # at least get the core message out if something happened
                    message = self.msg_fmt
        elif not isinstance(message, six.string_types):
            LOG.error(
                _("Message '%(msg)s' for %(ex)s exception is not " "a string"),
                {"msg": message, "ex": self.__class__.__name__},
            )
            if CONF.fatal_exception_format_errors:
                raise TypeError(_("Invalid exception message format"))
            else:
                message = self.msg_fmt

        super(EC2APIException, self).__init__(message)
def attach_network_interface(context, network_interface_id,
                             instance_id, device_index):
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    if 'instance_id' in network_interface:
        raise exception.InvalidParameterValue(
            _("Network interface '%(id)s' is currently in use.") %
            {'id': network_interface_id})
    os_instance_id = ec2utils.get_db_item(context, instance_id)['os_id']
    # TODO(Alex) Check that the instance is not yet attached to another VPC
    # TODO(Alex) Check that the instance is "our", not created via nova
    # (which means that it doesn't belong to any VPC and can't be attached)
    if any(eni['device_index'] == device_index
           for eni in db_api.get_items(context, 'eni')
           if eni.get('instance_id') == instance_id):
        raise exception.InvalidParameterValue(
            _("Instance '%(id)s' already has an interface attached at "
              "device index '%(index)s'.") % {'id': instance_id,
                                              'index': device_index})
    neutron = clients.neutron(context)
    os_port = neutron.show_port(network_interface['os_id'])['port']
    nova = clients.nova(context)
    with common.OnCrashCleaner() as cleaner:
        # TODO(Alex) nova inserts compute:%availability_zone into device_owner
        #                              'device_owner': 'compute:None'}})
        _attach_network_interface_item(context, network_interface,
                                       instance_id, device_index)
        cleaner.addCleanup(_detach_network_interface_item, context,
                           network_interface)
        nova.servers.interface_attach(os_instance_id, os_port['id'],
                                      None, None)
    return {'attachmentId': ec2utils.change_ec2_id_kind(
                    network_interface['id'], 'eni-attach')}
Example #3
0
    def __init__(self, message=None, **kwargs):
        self.kwargs = kwargs

        if not message:
            try:
                message = self.msg_fmt % kwargs
            except Exception:
                exc_info = sys.exc_info()
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_('Exception in string format operation for '
                                '%s exception'), self.__class__.__name__)
                for name, value in six.iteritems(kwargs):
                    LOG.error('%s: %s' % (name, value))

                if CONF.fatal_exception_format_errors:
                    six.reraise(*exc_info)
                else:
                    # at least get the core message out if something happened
                    message = self.msg_fmt
        elif not isinstance(message, six.string_types):
            LOG.error(_("Message '%(msg)s' for %(ex)s exception is not "
                        "a string"),
                      {'msg': message, 'ex': self.__class__.__name__})
            if CONF.fatal_exception_format_errors:
                raise TypeError(_('Invalid exception message format'))
            else:
                message = self.msg_fmt

        super(EC2APIException, self).__init__(message)
Example #4
0
def _s3_decrypt_image(context, encrypted_filename, encrypted_key,
                      encrypted_iv, decrypted_filename):
    encrypted_key = binascii.a2b_hex(encrypted_key)
    encrypted_iv = binascii.a2b_hex(encrypted_iv)
    cert_client = clients.nova_cert(context)
    try:
        key = cert_client.decrypt_text(base64.b64encode(encrypted_key))
    except Exception as exc:
        msg = _('Failed to decrypt private key: %s') % exc
        raise exception.EC2Exception(msg)
    try:
        iv = cert_client.decrypt_text(base64.b64encode(encrypted_iv))
    except Exception as exc:
        msg = _('Failed to decrypt initialization vector: %s') % exc
        raise exception.EC2Exception(msg)

    try:
        processutils.execute('openssl', 'enc',
                             '-d', '-aes-128-cbc',
                             '-in', '%s' % (encrypted_filename,),
                             '-K', '%s' % (key,),
                             '-iv', '%s' % (iv,),
                             '-out', '%s' % (decrypted_filename,))
    except processutils.ProcessExecutionError as exc:
        raise exception.EC2Exception(_('Failed to decrypt image file '
                                       '%(image_file)s: %(err)s') %
                                     {'image_file': encrypted_filename,
                                      'err': exc.stdout})
def attach_internet_gateway(context, internet_gateway_id, vpc_id):
    igw = ec2utils.get_db_item(context, internet_gateway_id)
    if igw.get('vpc_id'):
        msg_params = {'igw_id': igw['id'],
                      'vpc_id': igw['vpc_id']}
        msg = _('resource %(igw_id)s is already attached to '
                'network %(vpc_id)s') % msg_params
        raise exception.ResourceAlreadyAssociated(msg)
    vpc = ec2utils.get_db_item(context, vpc_id)
    if ec2utils.get_attached_gateway(context, vpc['id'], 'igw'):
        msg = _('Network %(vpc_id)s already has an internet gateway '
                'attached') % {'vpc_id': vpc['id']}
        raise exception.InvalidParameterValue(msg)

    external_network_id = None
    if not ec2utils.get_attached_gateway(context, vpc['id'], 'vgw'):
        external_network_id = ec2utils.get_os_public_network(context)['id']
    neutron = clients.neutron(context)

    # TODO(ft): set attaching state into db
    with common.OnCrashCleaner() as cleaner:
        _attach_internet_gateway_item(context, igw, vpc['id'])
        cleaner.addCleanup(_detach_internet_gateway_item, context, igw)
        if external_network_id:
            neutron.add_gateway_router(vpc['os_id'],
                                       {'network_id': external_network_id})
    return True
Example #6
0
def validate_security_group_str(value, parameter_name, vpc_id=None):
    # NOTE(Alex) Amazon accepts any ASCII for EC2 classic;
    # for EC2-VPC: a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=&;{}!$*
    if vpc_id:
        allowed = '^[a-zA-Z0-9\._\-:/\(\)#,@\[\]\+=&;\{\}!\$\*\ ]+$'
    else:
        allowed = r'^[\x20-\x7E]+$'
    msg = ''
    try:
        val = value.strip()
    except AttributeError:
        msg = (_("Security group %s is not a string or unicode") %
               parameter_name)
    if not val:
        msg = _("Security group %s cannot be empty.") % parameter_name
    elif not re.match(allowed, val):
        msg = (_("Specified value for parameter Group%(property)s is "
                 "invalid. Content limited to '%(allowed)s'.") %
               {'allowed': 'allowed',
                'property': parameter_name})
    elif len(val) > 255:
        msg = _("Security group %s should not be greater "
                "than 255 characters.") % parameter_name
    if msg:
        raise exception.ValidationError(reason=msg)
    return True
Example #7
0
    def _unpack_neutron_request(self, req):
        os_instance_id = req.headers.get('X-Instance-ID')
        project_id = req.headers.get('X-Tenant-ID')
        signature = req.headers.get('X-Instance-ID-Signature')
        remote_ip = req.headers.get('X-Forwarded-For')

        if not remote_ip:
            raise exception.EC2MetadataInvalidAddress()

        if os_instance_id is None:
            msg = _('X-Instance-ID header is missing from request.')
        elif project_id is None:
            msg = _('X-Tenant-ID header is missing from request.')
        elif not isinstance(os_instance_id, six.string_types):
            msg = _('Multiple X-Instance-ID headers found within request.')
        elif not isinstance(project_id, six.string_types):
            msg = _('Multiple X-Tenant-ID headers found within request.')
        else:
            msg = None

        if msg:
            raise webob.exc.HTTPBadRequest(explanation=msg)

        self._validate_signature(signature, os_instance_id, remote_ip)
        return os_instance_id, project_id, remote_ip
Example #8
0
def delete_vpn_connection(context, vpn_connection_id):
    vpn_connection = ec2utils.get_db_item(context, vpn_connection_id)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, vpn_connection['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'vpn', vpn_connection)
        neutron = clients.neutron(context)
        _stop_vpn_connection(neutron, vpn_connection)
        try:
            neutron.delete_ipsecpolicy(vpn_connection['os_ipsecpolicy_id'])
        except neutron_exception.Conflict as ex:
            LOG.warning(
                _('Failed to delete ipsecoplicy %(os_id)s during deleting '
                  'VPN connection %(id)s. Reason: %(reason)s'),
                {'id': vpn_connection['id'],
                 'os_id': vpn_connection['os_ipsecpolicy_id'],
                 'reason': ex.message})
        except neutron_exception.NotFound:
            pass
        try:
            neutron.delete_ikepolicy(vpn_connection['os_ikepolicy_id'])
        except neutron_exception.Conflict as ex:
            LOG.warning(
                _('Failed to delete ikepolicy %(os_id)s during deleting '
                  'VPN connection %(id)s. Reason: %(reason)s'),
                {'id': vpn_connection['id'],
                 'os_id': vpn_connection['os_ikepolicy_id'],
                 'reason': ex.message})
        except neutron_exception.NotFound:
            pass
    return True
Example #9
0
def ec2_error_ex(ex, req, unexpected=False):
    """Return an EC2 error response.

    Return an EC2 error response based on passed exception and log
    the exception on an appropriate log level:

        * DEBUG: expected errors
        * ERROR: unexpected errors

    All expected errors are treated as client errors and 4xx HTTP
    status codes are always returned for them.

    Unexpected 5xx errors may contain sensitive information,
    suppress their messages for security.
    """
    code = exception_to_ec2code(ex)
    for status_name in ('code', 'status', 'status_code', 'http_status'):
        status = getattr(ex, status_name, None)
        if isinstance(status, int):
            break
    else:
        status = 500

    if unexpected:
        log_fun = LOG.error
        log_msg = _("Unexpected %(ex_name)s raised: %(ex_str)s")
        exc_info = sys.exc_info()
    else:
        log_fun = LOG.debug
        log_msg = _("%(ex_name)s raised: %(ex_str)s")
        exc_info = None

    context = req.environ['ec2api.context']
    request_id = context.request_id
    log_msg_args = {
        'ex_name': type(ex).__name__,
        'ex_str': ex
    }
    log_fun(log_msg % log_msg_args, context=context, exc_info=exc_info)

    if unexpected and status >= 500:
        message = _('Unknown error occurred.')
    elif getattr(ex, 'message', None):
        message = six.text_type(ex.message)
    elif ex.args and any(arg for arg in ex.args):
        message = " ".join(map(six.text_type, ex.args))
    else:
        message = six.text_type(ex)
    if unexpected:
        # Log filtered environment for unexpected errors.
        env = req.environ.copy()
        for k in list(env.keys()):
            if not isinstance(env[k], six.string_types):
                env.pop(k)
        log_fun(_('Environment: %s') % jsonutils.dumps(env))
    return faults.ec2_error_response(request_id, code, message, status=status)
Example #10
0
def disassociate_address(context, public_ip=None, association_id=None):
    if not public_ip and not association_id:
        msg = _('Either public IP or association id must be specified')
        raise exception.MissingParameter(msg)
    if public_ip and association_id:
        msg = _('You may specify public IP or association id, '
                'but not both in the same call')
        raise exception.InvalidParameterCombination(msg)
    address_engine.disassociate_address(context, public_ip, association_id)
    return True
Example #11
0
    def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None,
                 protocol=eventlet.wsgi.HttpProtocol, backlog=128,
                 use_ssl=False, max_url_len=None):
        """Initialize, but do not start, a WSGI server.

        :param name: Pretty name for logging.
        :param app: The WSGI application to serve.
        :param host: IP address to serve the application.
        :param port: Port number to server the application.
        :param pool_size: Maximum number of eventlets to spawn concurrently.
        :param backlog: Maximum number of queued connections.
        :param max_url_len: Maximum length of permitted URLs.
        :returns: None
        :raises: ec2api.exception.InvalidInput
        """
        # Allow operators to customize http requests max header line size.
        eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line
        self.name = name
        self.app = app
        self._server = None
        self._protocol = protocol
        self.pool_size = pool_size or self.default_pool_size
        self._pool = eventlet.GreenPool(self.pool_size)
        self._logger = logging.getLogger("ec2api.wsgi.server")
        self._use_ssl = use_ssl
        self._max_url_len = max_url_len

        if backlog < 1:
            raise exception.InvalidInput(
                    reason='The backlog must be more than 1')

        bind_addr = (host, port)
        # TODO(dims): eventlet's green dns/socket module does not actually
        # support IPv6 in getaddrinfo(). We need to get around this in the
        # future or monitor upstream for a fix
        try:
            info = socket.getaddrinfo(bind_addr[0],
                                      bind_addr[1],
                                      socket.AF_UNSPEC,
                                      socket.SOCK_STREAM)[0]
            family = info[0]
            bind_addr = info[-1]
        except Exception:
            family = socket.AF_INET

        try:
            self._socket = eventlet.listen(bind_addr, family, backlog=backlog)
        except EnvironmentError:
            LOG.error(_("Could not bind to %(host)s:%(port)s"),
                      {'host': host, 'port': port})
            raise

        (self.host, self.port) = self._socket.getsockname()[0:2]
        LOG.info(_("%(name)s listening on %(host)s:%(port)s"),
                 {'name': self.name, 'host': self.host, 'port': self.port})
Example #12
0
    def disassociate_address(self, context, public_ip=None,
                             association_id=None):
        neutron = clients.neutron(context)

        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in db_api.get_items(context,
                                                              'eipalloc')
                            if addr['public_ip'] == public_ip), None)

            if not CONF.disable_ec2_classic:
                if address and _is_address_valid(context, neutron, address):
                    msg = _('You must specify an association id when '
                            'unmapping an address from a VPC instance')
                    raise exception.InvalidParameterValue(msg)
                # NOTE(tikitavi): check the public IP exists to raise AWS
                # exception otherwise
                os_floating_ip = self.get_os_floating_ip_by_public_ip(
                    context, public_ip)
                os_ports = self.get_os_ports(context)
                os_instance_id = _get_os_instance_id(context, os_floating_ip,
                                                     os_ports)
                if os_instance_id:
                    nova = clients.nova(context)
                    nova.servers.remove_floating_ip(os_instance_id, public_ip)
                return None

            if not address:
                msg = _("The address '%(public_ip)s' does not belong to you.")
                raise exception.AuthFailure(msg % {'public_ip': public_ip})
            if 'network_interface_id' not in address:
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            association_id = ec2utils.change_ec2_id_kind(address['id'],
                                                         'eipassoc')

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(
                    id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                neutron.update_floatingip(address['os_id'],
                                          {'floatingip': {'port_id': None}})
Example #13
0
def _validate_parameters(protocol, from_port, to_port):
    if (not isinstance(protocol, int) and
            protocol not in ['tcp', 'udp', 'icmp']):
        raise exception.InvalidParameterValue(
            _('Invalid value for IP protocol. Unknown protocol.'))
    if (not isinstance(from_port, int) or
            not isinstance(to_port, int)):
        raise exception.InvalidParameterValue(
            _('Integer values should be specified for ports'))
    if protocol in ['tcp', 'udp', 6, 17]:
        if from_port == -1 or to_port == -1:
            raise exception.InvalidParameterValue(
                _('Must specify both from and to ports with TCP/UDP.'))
        if from_port > to_port:
            raise exception.InvalidParameterValue(
                _('Invalid TCP/UDP port range.'))
        if from_port < 0 or from_port > 65535:
            raise exception.InvalidParameterValue(
                _('TCP/UDP from port is out of range.'))
        if to_port < 0 or to_port > 65535:
            raise exception.InvalidParameterValue(
                _('TCP/UDP to port is out of range.'))
    elif protocol in ['icmp', 1]:
        if from_port < -1 or from_port > 255:
            raise exception.InvalidParameterValue(
                _('ICMP type is out of range.'))
        if to_port < -1 or to_port > 255:
            raise exception.InvalidParameterValue(
                _('ICMP code is out of range.'))
Example #14
0
    def _proxy_request(self, req, requester):
        headers = self._build_proxy_request_headers(requester)
        nova_ip_port = '%s:%s' % (CONF.metadata.nova_metadata_ip,
                                  CONF.metadata.nova_metadata_port)
        url = urlparse.urlunsplit((
            CONF.metadata.nova_metadata_protocol,
            nova_ip_port,
            req.path_info,
            req.query_string,
            ''))

        h = httplib2.Http(
            ca_certs=CONF.metadata.auth_ca_cert,
            disable_ssl_certificate_validation=(
                    CONF.metadata.nova_metadata_insecure)
        )
        if (CONF.metadata.nova_client_cert and
                CONF.metadata.nova_client_priv_key):
            h.add_certificate(CONF.metadata.nova_client_priv_key,
                              CONF.metadata.nova_client_cert,
                              nova_ip_port)
        resp, content = h.request(url, method=req.method, headers=headers,
                                  body=req.body)

        if resp.status == 200:
            LOG.debug(str(resp))
            req.response.content_type = resp['content-type']
            req.response.body = content
            return req.response
        elif resp.status == 403:
            LOG.warning(
                'The remote metadata server responded with Forbidden. This '
                'response usually occurs when shared secrets do not match.'
            )
            return webob.exc.HTTPForbidden()
        elif resp.status == 400:
            return webob.exc.HTTPBadRequest()
        elif resp.status == 404:
            return webob.exc.HTTPNotFound()
        elif resp.status == 409:
            return webob.exc.HTTPConflict()
        elif resp.status == 500:
            msg = _(
                'Remote metadata server experienced an internal server error.'
            )
            LOG.warning(msg)
            return webob.exc.HTTPInternalServerError(
                explanation=six.text_type(msg))
        else:
            raise Exception(_('Unexpected response code: %s') % resp.status)
Example #15
0
def delete_vpc(context, vpc_id):
    vpc = ec2utils.get_db_item(context, vpc_id)
    subnets = subnet_api.describe_subnets(
        context,
        filter=[{'name': 'vpc-id', 'value': [vpc_id]}])['subnetSet']
    internet_gateways = internet_gateway_api.describe_internet_gateways(
        context,
        filter=[{'name': 'attachment.vpc-id',
                 'value': [vpc['id']]}])['internetGatewaySet']
    route_tables = route_table_api.describe_route_tables(
        context,
        filter=[{'name': 'vpc-id', 'value': [vpc['id']]}])['routeTableSet']
    security_groups = security_group_api.describe_security_groups(
        context,
        filter=[{'name': 'vpc-id',
                 'value': [vpc['id']]}])['securityGroupInfo']
    vpn_gateways = vpn_gateway_api.describe_vpn_gateways(
        context,
        filter=[{'name': 'attachment.vpc-id',
                 'value': [vpc['id']]}])['vpnGatewaySet']
    if (subnets or internet_gateways or len(route_tables) > 1 or
            len(security_groups) > 1 or vpn_gateways):
        msg = _("The vpc '%(vpc_id)s' has dependencies and "
                "cannot be deleted.")
        msg = msg % {'vpc_id': vpc['id']}
        raise exception.DependencyViolation(msg)

    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, vpc['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'vpc', vpc)
        route_table_api._delete_route_table(context, vpc['route_table_id'],
                                            cleaner=cleaner)
        if len(security_groups) > 0:
            security_group_api.delete_security_group(
                context, group_id=security_groups[0]['groupId'],
                delete_default=True)
        try:
            neutron.delete_router(vpc['os_id'])
        except neutron_exception.Conflict as ex:
            LOG.warning(_('Failed to delete router %(os_id)s during deleting '
                          'VPC %(id)s. Reason: %(reason)s'),
                        {'id': vpc['id'],
                         'os_id': vpc['os_id'],
                         'reason': ex.message})
        except neutron_exception.NotFound:
            pass

    return True
Example #16
0
def validate_ec2_id(val, parameter_name, prefices):
    try:
        prefix, value = val.rsplit('-', 1)
        int(value, 16)
        if not prefices or prefix in prefices:
            return True
    except Exception:
        pass

    if not prefices:
        reason = _('Invalid EC2 id was specified.')
    else:
        reason = _('Expected: %(prefix)s-...') % {'prefix': prefices[0]}
    raise exception.InvalidParameterValue(
        value=val, parameter=parameter_name, reason=reason)
Example #17
0
    def __call__(self, req):
        LOG.debug('Request: %s', req)

        path = req.path_info
        if path == '' or path[0] != '/':
            path = '/' + path
        path = posixpath.normpath(path)
        path_tokens = path.split('/')[1:]
        if path_tokens[0] == 'ec2':
            path_tokens = path_tokens[1:]

        if path_tokens == ['']:
            resp = api.get_version_list()
            return self._add_response_data(req.response, resp)

        try:
            requester = self._get_requester(req)
            if path_tokens[0] == 'openstack':
                return self._proxy_request(req, requester)

            resp = self._get_metadata(path_tokens, requester)
            return self._add_response_data(req.response, resp)

        except exception.EC2MetadataNotFound:
            return webob.exc.HTTPNotFound()
        except Exception:
            LOG.exception("Unexpected error.")
            msg = _('An unknown error has occurred. '
                    'Please try your request again.')
            return webob.exc.HTTPInternalServerError(
                explanation=six.text_type(msg))
Example #18
0
    def _unpack_nsx_request(self, req):
        remote_address = req.headers.get('X-Forwarded-For')
        if remote_address is None:
            msg = _('X-Forwarded-For is missing from request.')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        provider_id = req.headers.get('X-Metadata-Provider')
        if provider_id is None:
            msg = _('X-Metadata-Provider is missing from request.')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        remote_ip = remote_address.split(',')[0]

        if CONF.metadata.metadata_proxy_shared_secret:
            signature = req.headers.get('X-Metadata-Provider-Signature')
            self._validate_signature(signature, provider_id, remote_ip)

        return provider_id, remote_ip
Example #19
0
def delete_route(context, route_table_id, destination_cidr_block):
    route_table = ec2utils.get_db_item(context, route_table_id)
    for route_index, route in enumerate(route_table['routes']):
        if route['destination_cidr_block'] != destination_cidr_block:
            continue
        if route.get('gateway_id', 0) is None:
            msg = _('cannot remove local route %(destination_cidr_block)s '
                    'in route table %(route_table_id)s')
            msg = msg % {'route_table_id': route_table_id,
                         'destination_cidr_block': destination_cidr_block}
            raise exception.InvalidParameterValue(msg)
        break
    else:
        raise exception.InvalidRouteNotFound(
            route_table_id=route_table_id,
            destination_cidr_block=destination_cidr_block)
    update_target = _get_route_target(route)
    if update_target == VPN_TARGET:
        vpn_gateway = db_api.get_item_by_id(context, route['gateway_id'])
        if (not vpn_gateway or
                vpn_gateway['vpc_id'] != route_table['vpc_id']):
            update_target = None
    rollback_route_table_state = copy.deepcopy(route_table)
    del route_table['routes'][route_index]
    with common.OnCrashCleaner() as cleaner:
        db_api.update_item(context, route_table)
        cleaner.addCleanup(db_api.update_item, context,
                           rollback_route_table_state)

        if update_target:
            _update_routes_in_associated_subnets(
                context, cleaner, route_table, update_target=update_target)

    return True
Example #20
0
def create_security_group(context, group_name, group_description,
                          vpc_id=None):
    if group_name == DEFAULT_GROUP_NAME:
        if vpc_id:
            raise exception.InvalidParameterValue(
                _('Cannot use reserved security group name: %s')
                % DEFAULT_GROUP_NAME)
        else:
            raise exception.InvalidGroupReserved(group_name=group_name)
    filter = [{'name': 'group-name',
               'value': [group_name]}]
    if vpc_id and group_name != vpc_id:
        filter.append({'name': 'vpc-id',
                       'value': [vpc_id]})
    security_groups = describe_security_groups(
        context, filter=filter)['securityGroupInfo']
    if not vpc_id:
        # TODO(andrey-mp): remove it when fitering by None will be implemented
        security_groups = [sg for sg in security_groups
                           if sg.get('vpcId') is None]
    if security_groups:
        raise exception.InvalidGroupDuplicate(name=group_name)

    return _create_security_group(context, group_name, group_description,
                                  vpc_id)
Example #21
0
def delete_vpn_gateway(context, vpn_gateway_id):
    vpn_gateway = ec2utils.get_db_item(context, vpn_gateway_id)
    vpn_connections = db_api.get_items(context, "vpn")
    if vpn_gateway["vpc_id"] or any(vpn["vpn_gateway_id"] == vpn_gateway["id"] for vpn in vpn_connections):
        raise exception.IncorrectState(reason=_("The VPN gateway is in use."))
    db_api.delete_item(context, vpn_gateway["id"])
    return True
Example #22
0
    def __call__(self, environ, start_response):
        r"""Subclasses will probably want to implement __call__ like this:

        @webob.dec.wsgify(RequestClass=Request)
        def __call__(self, req):
          # Any of the following objects work as responses:

          # Option 1: simple string
          res = 'message\n'

          # Option 2: a nicely formatted HTTP exception page
          res = exc.HTTPForbidden(explanation='Nice try')

          # Option 3: a webob Response object (in case you need to play with
          # headers, or you want to be treated like an iterable, or or or)
          res = Response();
          res.app_iter = open('somefile')

          # Option 4: any wsgi app to be run next
          res = self.application

          # Option 5: you can get a Response object for a wsgi app, too, to
          # play with headers etc
          res = req.get_response(self.application)

          # You can then just return your response...
          return res
          # ... or set req.response and return None.
          req.response = res

        See the end of http://pythonpaste.org/webob/modules/dec.html
        for more info.

        """
        raise NotImplementedError(_('You must implement __call__'))
Example #23
0
    def disassociate_address(self, context, public_ip=None,
                             association_id=None):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in db_api.get_items(context,
                                                              'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            # NOTE(ft): association_id is unused in EC2 Classic mode, but it's
            # passed there to validate its emptiness in one place
            return AddressEngineNova().disassociate_address(
                    context, public_ip=public_ip,
                    association_id=association_id)

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(
                    id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                neutron.update_floatingip(address['os_id'],
                                          {'floatingip': {'port_id': None}})
Example #24
0
def allocate_address(context, domain=None):
    if domain and domain not in ['vpc', 'standard']:
        msg = _("Invalid value '%(domain)s' for domain.") % {'domain': domain}
        raise exception.InvalidParameterValue(msg)

    address, os_floating_ip = address_engine.allocate_address(context, domain)
    return _format_address(context, address, os_floating_ip)
Example #25
0
def revoke_security_group_egress(context, group_id, ip_permissions=None):
    security_group = ec2utils.get_db_item(context, group_id)
    if not security_group.get('vpc_id'):
        raise exception.InvalidParameterValue(message=_('Only Amazon VPC '
            'security groups may be used with this operation.'))
    return _revoke_security_group(context, group_id, None,
                                  ip_permissions, 'egress')
Example #26
0
def validate_str(val, parameter_name, max_length=None):
    if (isinstance(val, six.string_types) and
            (max_length is None or max_length and len(val) <= max_length)):
        return True
    raise exception.ValidationError(
        reason=_("%s should not be greater "
                 "than 255 characters.") % parameter_name)
Example #27
0
    def __init__(self, name, loader=None, max_url_len=None):
        """Initialize, but do not start the WSGI server.

        :param name: The name of the WSGI server given to the loader.
        :param loader: Loads the WSGI application using the given name.
        :returns: None

        """
        self.name = name
        self.manager = self._get_manager()
        self.loader = loader or wsgi.Loader()
        self.app = self.loader.load_app(name)
        self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
        self.port = getattr(CONF, '%s_listen_port' % name, 0)
        self.use_ssl = getattr(CONF, '%s_use_ssl' % name, False)
        self.workers = (getattr(CONF, '%s_workers' % name, None) or
                        processutils.get_worker_count())
        if self.workers and self.workers < 1:
            worker_name = '%s_workers' % name
            msg = (_("%(worker_name)s value of %(workers)s is invalid, "
                     "must be greater than 0") %
                   {'worker_name': worker_name,
                    'workers': str(self.workers)})
            raise exception.InvalidInput(msg)
        self.server = wsgi.Server(name,
                                  self.app,
                                  host=self.host,
                                  port=self.port,
                                  use_ssl=self.use_ssl,
                                  max_url_len=max_url_len)
        # Pull back actual port used
        self.port = self.server.port
Example #28
0
def validate_key_value_dict_list(dict_list, parameter_name):
    for dict in dict_list:
        if not dict.get('key') or dict.get('value') is None:
            raise exception.InvalidParameterValue(
                value=dict, parameter=parameter_name,
                reason=_('Expected list of key value dictionaries'))
    return True
Example #29
0
def disassociate_route_table(context, association_id):
    subnet = db_api.get_item_by_id(
        context, ec2utils.change_ec2_id_kind(association_id, 'subnet'))
    if not subnet:
        vpc = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'vpc'))
        if vpc is None:
            raise exception.InvalidAssociationIDNotFound(id=association_id)
        msg = _('Cannot disassociate the main route table association '
                '%(rtbassoc_id)s') % {'rtbassoc_id': association_id}
        raise exception.InvalidParameterValue(msg)
    if 'route_table_id' not in subnet:
        raise exception.InvalidAssociationIDNotFound(id=association_id)

    rollback_route_table_id = subnet['route_table_id']
    vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
    main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
    with common.OnCrashCleaner() as cleaner:
        _disassociate_subnet_item(context, subnet)
        cleaner.addCleanup(_associate_subnet_item, context, subnet,
                           rollback_route_table_id)

        _update_subnet_routes(context, cleaner, subnet, main_route_table)

    return True
Example #30
0
    def release_address(self, context, public_ip, allocation_id):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in
                            db_api.get_items(context, 'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an allocation id when releasing a '
                        'VPC elastic IP address')
                raise exception.InvalidParameterValue(msg)
            return AddressEngineNova().release_address(context,
                                                       public_ip, None)

        address = ec2utils.get_db_item(context, allocation_id)
        if not _is_address_valid(context, neutron, address):
            raise exception.InvalidAllocationIDNotFound(
                id=allocation_id)
        if 'network_interface_id' in address:
            raise exception.InvalidIPAddressInUse(
                ip_address=address['public_ip'])

        with common.OnCrashCleaner() as cleaner:
            db_api.delete_item(context, address['id'])
            cleaner.addCleanup(db_api.restore_item, context,
                               'eipalloc', address)
            try:
                neutron.delete_floatingip(address['os_id'])
            except neutron_exception.NotFound:
                pass
Example #31
0
 def get_nova_ip_by_public_ip(self,
                              context,
                              public_ip,
                              nova_floating_ips=None):
     if nova_floating_ips is None:
         nova = clients.nova(context)
         nova_floating_ips = nova.floating_ips.list()
     nova_ip = next((ip for ip in nova_floating_ips if ip.ip == public_ip),
                    None)
     if nova_ip is None:
         msg = _("The address '%(public_ip)s' does not belong to you.")
         raise exception.AuthFailure(msg % {'public_ip': public_ip})
     return nova_ip
Example #32
0
    def wait(self):
        """Block, until the server has stopped.

        Waits on the server's eventlet to finish, then returns.

        :returns: None

        """
        try:
            if self._server is not None:
                self._server.wait()
        except greenlet.GreenletExit:
            LOG.info(_("WSGI server has stopped."))
Example #33
0
def is_ec2_timestamp_expired(request, expires=None):
    """Checks the timestamp or expiry time included in an EC2 request

    and returns true if the request is expired
    """
    query_time = None
    timestamp = request.get('Timestamp')
    expiry_time = request.get('Expires')

    def parse_strtime(strtime):
        if _ms_time_regex.match(strtime):
            # NOTE(MotoKen): time format for aws-sdk-java contains millisecond
            time_format = "%Y-%m-%dT%H:%M:%S.%fZ"
        else:
            time_format = "%Y-%m-%dT%H:%M:%SZ"
        return timeutils.parse_strtime(strtime, time_format)

    try:
        if timestamp and expiry_time:
            msg = _("Request must include either Timestamp or Expires,"
                    " but cannot contain both")
            LOG.error(msg)
            raise exception.InvalidRequest(msg)
        elif expiry_time:
            query_time = parse_strtime(expiry_time)
            return timeutils.is_older_than(query_time, -1)
        elif timestamp:
            query_time = parse_strtime(timestamp)

            # Check if the difference between the timestamp in the request
            # and the time on our servers is larger than 5 minutes, the
            # request is too old (or too new).
            if query_time and expires:
                return (timeutils.is_older_than(query_time, expires) or
                        timeutils.is_newer_than(query_time, expires))
        return False
    except ValueError:
        LOG.exception(_("Timestamp is invalid: "))
        return True
Example #34
0
def import_key_pair(context, key_name, public_key_material):
    _validate_name(key_name)
    if not public_key_material:
        raise exception.MissingParameter(
            _('The request must contain the parameter PublicKeyMaterial'))
    nova = clients.nova(context)
    public_key = base64.b64decode(public_key_material).decode("utf-8")
    try:
        key_pair = nova.keypairs.create(key_name, public_key)
    except nova_exception.OverLimit:
        raise exception.ResourceLimitExceeded(resource='keypairs')
    except nova_exception.Conflict:
        raise exception.InvalidKeyPairDuplicate(key_name=key_name)
    return _format_key_pair(key_pair)
Example #35
0
def modify_network_interface_attribute(context,
                                       network_interface_id,
                                       description=None,
                                       source_dest_check=None,
                                       security_group_id=None,
                                       attachment=None):
    params_count = (int(description is not None) +
                    int(source_dest_check is not None) +
                    int(security_group_id is not None) +
                    int(attachment is not None))
    if params_count != 1:
        raise exception.InvalidParameterCombination(
            'Multiple attributes specified')
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    if description is not None:
        network_interface['description'] = description
        db_api.update_item(context, network_interface)
    neutron = clients.neutron(context)
    if security_group_id is not None:
        os_groups = [
            sg['os_id']
            for sg in ec2utils.get_db_items(context, 'sg', security_group_id)
        ]
        neutron.update_port(network_interface['os_id'],
                            {'port': {
                                'security_groups': os_groups
                            }})
    if source_dest_check is not None:
        allowed = [] if source_dest_check else [{'ip_address': '0.0.0.0/0'}]
        neutron.update_port(network_interface['os_id'],
                            {'port': {
                                'allowed_address_pairs': allowed
                            }})
        network_interface['source_dest_check'] = source_dest_check
        db_api.update_item(context, network_interface)
    if attachment:
        attachment_id = attachment.get('attachment_id')
        delete_on_termination = attachment.get('delete_on_termination')
        if attachment_id is None or delete_on_termination is None:
            raise exception.MissingParameter(
                _('The request must contain the parameter attachment '
                  'deleteOnTermination'))
        attachment_id_own = ec2utils.change_ec2_id_kind(
            network_interface['id'], 'eni-attach')
        if ('instance_id' not in network_interface
                or attachment_id_own != attachment_id):
            raise exception.InvalidAttachmentIDNotFound(id=attachment_id)
        network_interface['delete_on_termination'] = delete_on_termination
        db_api.update_item(context, network_interface)
    return True
Example #36
0
def associate_address(context,
                      public_ip=None,
                      instance_id=None,
                      allocation_id=None,
                      network_interface_id=None,
                      private_ip_address=None,
                      allow_reassociation=False):
    if not public_ip and not allocation_id:
        msg = _('Either public IP or allocation id must be specified')
        raise exception.MissingParameter(msg)
    if public_ip and allocation_id:
        msg = _('You may specify public IP or allocation id, '
                'but not both in the same call')
        raise exception.InvalidParameterCombination(msg)
    if not instance_id and not network_interface_id:
        msg = _('Either instance ID or network interface id must be specified')
        raise exception.MissingParameter(msg)
    associationId = address_engine.associate_address(
        context, public_ip, instance_id, allocation_id, network_interface_id,
        private_ip_address, allow_reassociation)
    if associationId:
        return {'return': True, 'associationId': associationId}
    return {'return': True}
Example #37
0
def associate_route_table(context, route_table_id, subnet_id):
    route_table = ec2utils.get_db_item(context, route_table_id)
    subnet = ec2utils.get_db_item(context, subnet_id)
    if route_table['vpc_id'] != subnet['vpc_id']:
        msg = _('Route table %(rtb_id)s and subnet %(subnet_id)s belong to '
                'different networks')
        msg = msg % {'rtb_id': route_table_id,
                     'subnet_id': subnet_id}
        raise exception.InvalidParameterValue(msg)
    if 'route_table_id' in subnet:
        msg = _('The specified association for route table %(rtb_id)s '
                'conflicts with an existing association')
        msg = msg % {'rtb_id': route_table_id}
        raise exception.ResourceAlreadyAssociated(msg)

    with common.OnCrashCleaner() as cleaner:
        _associate_subnet_item(context, subnet, route_table['id'])
        cleaner.addCleanup(_disassociate_subnet_item, context, subnet)

        _update_subnet_routes(context, cleaner, subnet, route_table)

    return {'associationId': ec2utils.change_ec2_id_kind(subnet['id'],
                                                         'rtbassoc')}
Example #38
0
    def describe(self, context, ids=None, names=None, filter=None,
                 max_results=None, next_token=None):
        if max_results and max_results < 5:
            msg = (_('Value ( %s ) for parameter maxResults is invalid. '
                     'Expecting a value greater than 5.') % max_results)
            raise exception.InvalidParameterValue(msg)

        self.context = context
        self.selective_describe = ids is not None or names is not None
        self.ids = set(ids or [])
        self.names = set(names or [])
        self.items = self.get_db_items()
        self.os_items = self.get_os_items()
        formatted_items = []

        self.items_dict = {i['os_id']: i for i in (self.items or [])}
        paired_items_ids = set()
        for os_item in self.os_items:
            os_item_name = self.get_name(os_item)
            os_item_id = self.get_id(os_item)
            item = self.items_dict.get(os_item_id, None)
            # NOTE(Alex): Filter out items not requested in names or ids
            if (self.selective_describe and
                    not (os_item_name in self.names or
                         (item and item['id'] in self.ids))):
                continue
            # NOTE(Alex): Autoupdate DB for autoupdatable items
            item = self.auto_update_db(item, os_item)
            if item:
                paired_items_ids.add(item['id'])
            formatted_item = self.format(item, os_item)
            self.post_format(formatted_item, item)
            if os_item_name in self.names:
                self.names.remove(os_item_name)
            if item and item['id'] in self.ids:
                self.ids.remove(item['id'])
            if (formatted_item and
                    not self.filtered_out(formatted_item, filter)):
                formatted_items.append(formatted_item)
        # NOTE(Alex): delete obsolete items
        for item in self.items:
            if item['id'] not in paired_items_ids:
                self.handle_unpaired_item(item, formatted_items)
        # NOTE(Alex): some requested items are not found
        if self.ids or self.names:
            params = {'id': next(iter(self.ids or self.names))}
            raise ec2utils.NOT_FOUND_EXCEPTION_MAP[self.KIND](**params)

        return self.get_paged(formatted_items, max_results, next_token)
Example #39
0
def attach_network_interface(context, network_interface_id, instance_id,
                             device_index):
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    if 'instance_id' in network_interface:
        raise exception.InvalidParameterValue(
            _("Network interface '%(id)s' is currently in use.") %
            {'id': network_interface_id})
    os_instance_id = ec2utils.get_db_item(context, instance_id)['os_id']
    # TODO(Alex) Check that the instance is not yet attached to another VPC
    # TODO(Alex) Check that the instance is "our", not created via nova
    # (which means that it doesn't belong to any VPC and can't be attached)
    if any(eni['device_index'] == device_index
           for eni in db_api.get_items(context, 'eni')
           if eni.get('instance_id') == instance_id):
        raise exception.InvalidParameterValue(
            _("Instance '%(id)s' already has an interface attached at "
              "device index '%(index)s'.") % {
                  'id': instance_id,
                  'index': device_index
              })
    neutron = clients.neutron(context)
    os_port = neutron.show_port(network_interface['os_id'])['port']
    nova = clients.nova(context)
    with common.OnCrashCleaner() as cleaner:
        # TODO(Alex) nova inserts compute:%availability_zone into device_owner
        #                              'device_owner': 'compute:None'}})
        _attach_network_interface_item(context, network_interface, instance_id,
                                       device_index)
        cleaner.addCleanup(_detach_network_interface_item, context,
                           network_interface)
        nova.servers.interface_attach(os_instance_id, os_port['id'], None,
                                      None)
    return {
        'attachmentId':
        ec2utils.change_ec2_id_kind(network_interface['id'], 'eni-attach')
    }
def create_tags(context, resource_id, tag):
    reason = None
    for tag_pair in tag:
        if not tag_pair.get('key'):
            reason = _('Not empty key must be present')
        elif len(tag_pair['key']) > 127:
            reason = _('Tag key exceeds the maximum length of 127 characters')
        elif tag_pair['key'].startswith('aws:'):
            reason = _("Tag keys starting with 'aws:' are reserved for "
                       "internal use")
        elif 'value' not in tag_pair:
            reason = _('Value must be present')
        elif len(tag_pair['value']) > 255:
            reason = _('Tag value exceeds the maximum length of 255 '
                       'characters')
        if reason:
            raise exception.InvalidParameterValue(parameter='Tag',
                                                  value=str(tag_pair),
                                                  reason=reason)

    for item_id in resource_id:
        kind = ec2utils.get_ec2_id_kind(item_id)
        if kind not in RESOURCE_TYPES:
            raise exception.InvalidID(id=item_id)
        # NOTE(ft): check items exist (excluding images because AWS allows to
        # create a tag with any image id)
        if kind not in ('jmi', 'jri', 'jki'):
            ec2utils.get_db_item(context, item_id)

    tags = [
        dict(item_id=item_id, key=tag_pair['key'], value=tag_pair['value'])
        for item_id in resource_id for tag_pair in tag
    ]

    db_api.add_tags(context, tags)
    return True
Example #41
0
    def stop(self):
        """Stop this server.

        This is not a very nice action, as currently the method by which a
        server is stopped is by killing its eventlet.

        :returns: None

        """
        LOG.info(_("Stopping WSGI server."))

        if self._server is not None:
            # Resize pool to stop new requests from being processed
            self._pool.resize(0)
            self._server.kill()
Example #42
0
def _delete_route_table(context, route_table_id, vpc=None, cleaner=None):
    def get_associated_subnets():
        return [s for s in db_api.get_items(context, 'subnet')
                if s.get('route_table_id') == route_table_id]

    if (vpc and route_table_id == vpc['route_table_id'] or
            len(get_associated_subnets()) > 0):
        msg = _("The routeTable '%(rtb_id)s' has dependencies and cannot "
                "be deleted.") % {'rtb_id': route_table_id}
        raise exception.DependencyViolation(msg)
    if cleaner:
        route_table = db_api.get_item_by_id(context, route_table_id)
    db_api.delete_item(context, route_table_id)
    if cleaner and route_table:
        cleaner.addCleanup(db_api.restore_item, context, 'rtb', route_table)
Example #43
0
class EC2APIException(Exception):
    """Base EC2 API Exception

    To correctly use this class, inherit from it and define
    a 'msg_fmt' property. That msg_fmt will get printf'd
    with the keyword arguments provided to the constructor.
    """
    msg_fmt = _('An unknown exception occurred.')

    def __init__(self, message=None, **kwargs):
        self.kwargs = kwargs

        if not message:
            try:
                message = self.msg_fmt % kwargs
            except Exception:
                exc_info = sys.exc_info()
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(
                    _('Exception in string format operation for '
                      '%s exception'), self.__class__.__name__)
                for name, value in six.iteritems(kwargs):
                    LOG.error('%s: %s' % (name, value))

                if CONF.fatal_exception_format_errors:
                    six.reraise(*exc_info)
                else:
                    # at least get the core message out if something happened
                    message = self.msg_fmt
        elif not isinstance(message, six.string_types):
            LOG.error(
                _("Message '%(msg)s' for %(ex)s exception is not "
                  "a string"), {
                      'msg': message,
                      'ex': self.__class__.__name__
                  })
            if CONF.fatal_exception_format_errors:
                raise TypeError(_('Invalid exception message format'))
            else:
                message = self.msg_fmt

        super(EC2APIException, self).__init__(message)

    def format_message(self):
        # NOTE(mrodden): use the first argument to the python Exception object
        # which should be our full EC2APIException message, (see __init__)
        return self.args[0]
Example #44
0
def describe_snapshots(context, snapshot_id=None, owner=None,
                       restorable_by=None, filter=None,
                       max_results=None, next_token=None):
    if snapshot_id and max_results:
        msg = _('The parameter snapshotSet cannot be used with the parameter '
                'maxResults')
        raise exception.InvalidParameterCombination(msg)

    snapshot_describer = SnapshotDescriber()
    formatted_snapshots = snapshot_describer.describe(
        context, ids=snapshot_id, filter=filter,
        max_results=max_results, next_token=next_token)
    result = {'snapshotSet': formatted_snapshots}
    if snapshot_describer.next_token:
        result['nextToken'] = snapshot_describer.next_token
    return result
Example #45
0
    def load_app(self, name):
        """Return the paste URLMap wrapped WSGI application.

        :param name: Name of the application to load.
        :returns: Paste URLMap object wrapping the requested application.
        :raises: `ec2api.exception.EC2APIPasteAppNotFound`

        """
        try:
            LOG.debug(_("Loading app %(name)s from %(path)s") %
                      {'name': name, 'path': self.config_path})
            return deploy.loadapp("config:%s" % self.config_path, name=name)
        except LookupError as err:
            LOG.error(err)
            raise exception.EC2APIPasteAppNotFound(name=name,
                                                   path=self.config_path)
Example #46
0
    def release_address(self, context, public_ip, allocation_id):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr
                            for addr in db_api.get_items(context, 'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an allocation id when releasing a '
                        'VPC elastic IP address')
                raise exception.InvalidParameterValue(msg)
            return AddressEngineNova().release_address(context, public_ip,
                                                       None)

        address = ec2utils.get_db_item(context, allocation_id)
        if not _is_address_valid(context, neutron, address):
            raise exception.InvalidAllocationIDNotFound(id=allocation_id)

        if 'network_interface_id' in address:
            if CONF.disable_ec2_classic:
                network_interface_id = address['network_interface_id']
                network_interface = db_api.get_item_by_id(
                    context, network_interface_id)
                default_vpc = ec2utils.check_and_create_default_vpc(context)
                if default_vpc:
                    default_vpc_id = default_vpc['id']
                if (network_interface
                        and network_interface['vpc_id'] == default_vpc_id):
                    association_id = ec2utils.change_ec2_id_kind(
                        address['id'], 'eipassoc')
                    self.disassociate_address(context,
                                              association_id=association_id)
                else:
                    raise exception.InvalidIPAddressInUse(
                        ip_address=address['public_ip'])
            else:
                raise exception.InvalidIPAddressInUse(
                    ip_address=address['public_ip'])

        with common.OnCrashCleaner() as cleaner:
            db_api.delete_item(context, address['id'])
            cleaner.addCleanup(db_api.restore_item, context, 'eipalloc',
                               address)
            try:
                neutron.delete_floatingip(address['os_id'])
            except neutron_exception.NotFound:
                pass
Example #47
0
def describe_network_interface_attribute(context,
                                         network_interface_id,
                                         attribute=None):
    if attribute is None:
        raise exception.InvalidParameterCombination(
            _('No attributes specified.'))
    network_interface = ec2utils.get_db_item(context, network_interface_id)

    def _format_attr_description(result):
        result['description'] = {
            'value': network_interface.get('description', '')
        }

    def _format_attr_source_dest_check(result):
        result['sourceDestCheck'] = {
            'value': network_interface.get('source_dest_check', True)
        }

    def _format_attr_group_set(result):
        ec2_network_interface = describe_network_interfaces(
            context, network_interface_id=[network_interface_id
                                           ])['networkInterfaceSet'][0]
        result['groupSet'] = ec2_network_interface['groupSet']

    def _format_attr_attachment(result):
        ec2_network_interface = describe_network_interfaces(
            context, network_interface_id=[network_interface_id
                                           ])['networkInterfaceSet'][0]
        if 'attachment' in ec2_network_interface:
            result['attachment'] = ec2_network_interface['attachment']

    attribute_formatter = {
        'description': _format_attr_description,
        'sourceDestCheck': _format_attr_source_dest_check,
        'groupSet': _format_attr_group_set,
        'attachment': _format_attr_attachment,
    }

    fn = attribute_formatter.get(attribute)
    if fn is None:
        raise exception.InvalidParameterValue(value=attribute,
                                              parameter='attribute',
                                              reason='Unknown attribute.')

    result = {'networkInterfaceId': network_interface['id']}
    fn(result)
    return result
Example #48
0
def db_version():
    repository = _find_migrate_repo()
    try:
        return versioning_api.db_version(get_engine(), repository)
    except versioning_exceptions.DatabaseNotControlledError:
        meta = sqlalchemy.MetaData()
        engine = get_engine()
        meta.reflect(bind=engine)
        tables = meta.tables
        if len(tables) == 0:
            db_version_control(INIT_VERSION)
            return versioning_api.db_version(get_engine(), repository)
        else:
            # Some pre-Essex DB's may not be version controlled.
            # Require them to upgrade using Essex first.
            raise exception.EC2Exception(
                _("Upgrade DB using Essex release first."))
Example #49
0
def get_os_public_network(context):
    neutron = clients.neutron(context)
    search_opts = {'router:external': True, 'name': CONF.external_network}
    os_networks = neutron.list_networks(**search_opts)['networks']
    if len(os_networks) != 1:
        if CONF.external_network:
            if len(os_networks) == 0:
                msg = "No external network with name '%s' is found"
            else:
                msg = "More than one external network with name '%s' is found"
            LOG.error(msg, CONF.external_network)
        else:
            if len(os_networks) == 0:
                msg = 'No external network is found'
            else:
                msg = 'More than one external network is found'
            LOG.error(msg)
        raise exception.Unsupported(_('Feature is restricted by OS admin'))
    return os_networks[0]
Example #50
0
def delete_subnet(context, subnet_id):
    subnet = ec2utils.get_db_item(context, subnet_id)
    vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
    network_interfaces = network_interface_api.describe_network_interfaces(
        context, filter=[{
            'name': 'subnet-id',
            'value': [subnet_id]
        }])['networkInterfaceSet']
    if network_interfaces:
        msg = _("The subnet '%(subnet_id)s' has dependencies and "
                "cannot be deleted.") % {
                    'subnet_id': subnet_id
                }
        raise exception.DependencyViolation(msg)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, subnet['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'subnet', subnet)
        vpn_gateway_api._stop_vpn_in_subnet(context, neutron, cleaner, subnet)
        try:
            neutron.remove_interface_router(vpc['os_id'],
                                            {'subnet_id': subnet['os_id']})
        except neutron_exception.NotFound:
            pass
        cleaner.addCleanup(neutron.add_interface_router, vpc['os_id'],
                           {'subnet_id': subnet['os_id']})
        try:
            os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
        except neutron_exception.NotFound:
            pass
        else:
            try:
                neutron.delete_network(os_subnet['network_id'])
            except neutron_exception.NetworkInUseClient as ex:
                LOG.warning(
                    'Failed to delete network %(os_id)s during '
                    'deleting Subnet %(id)s. Reason: %(reason)s', {
                        'id': subnet['id'],
                        'os_id': os_subnet['network_id'],
                        'reason': ex.message
                    })

    return True
Example #51
0
    def delayed_create(context, image, name, os_instance):
        try:
            os_instance.stop()

            # wait instance for really stopped
            start_time = time.time()
            while os_instance.status != 'SHUTOFF':
                time.sleep(1)
                os_instance.get()
                # NOTE(yamahata): timeout and error. 1 hour for now for safety.
                #                 Is it too short/long?
                #                 Or is there any better way?
                timeout = 1 * 60 * 60
                if time.time() > start_time + timeout:
                    err = (_("Couldn't stop instance within %d sec") % timeout)
                    raise exception.EC2Exception(message=err)

            # NOTE(ft): create an image with ec2_id metadata to let other code
            # link os and db objects in race conditions
            os_image_id = os_instance.create_image(
                name, metadata={'ec2_id': image['id']})
            image['os_id'] = os_image_id
            db_api.update_item(context, image)
        except Exception:
            LOG.exception(_LE('Failed to complete image %s creation'),
                          image.id)
            try:
                image['state'] = 'failed'
                db_api.update_item(context, image)
            except Exception:
                LOG.warning(_LW("Couldn't set 'failed' state for db image %s"),
                            image.id,
                            exc_info=True)

        try:
            os_instance.start()
        except Exception:
            LOG.warning(_LW('Failed to start instance %(i_id)s after '
                            'completed creation of image %(image_id)s'), {
                                'i_id': instance['id'],
                                'image_id': image['id']
                            },
                        exc_info=True)
Example #52
0
def _get_ec2_instance_and_reservation(context, os_instance_id):
    instance_id = ec2utils.os_id_to_ec2_id(context, 'i', os_instance_id)
    try:
        ec2_reservations = instance_api.describe_instances(
                context, [instance_id])
    except exception.InvalidInstanceIDNotFound:
        ec2_reservations = instance_api.describe_instances(
                context, filter=[{'name': 'instance-id',
                                  'value': [instance_id]}])
    if (len(ec2_reservations['reservationSet']) != 1 or
            len(ec2_reservations['reservationSet'][0]['instancesSet']) != 1):
        LOG.error(_('Failed to get metadata for instance id: %s'),
                  os_instance_id)
        raise exception.EC2MetadataNotFound()

    ec2_reservation = ec2_reservations['reservationSet'][0]
    ec2_instance = ec2_reservation['instancesSet'][0]

    return ec2_instance, ec2_reservation
Example #53
0
    def __get_backend(self):
        if not self.__backend:
            if self.__config_group is None:
                backend_name = CONF[self.__pivot]
            else:
                backend_name = CONF[self.__config_group][self.__pivot]
            if backend_name not in self.__backends:
                msg = _('Invalid backend: %s') % backend_name
                raise exception.EC2Exception(msg)

            backend = self.__backends[backend_name]
            if isinstance(backend, tuple):
                name = backend[0]
                fromlist = backend[1]
            else:
                name = backend
                fromlist = backend

            self.__backend = __import__(name, None, None, fromlist)
        return self.__backend
Example #54
0
    def describe(self, context, ids=None, names=None, filter=None,
                 max_results=None, next_token=None):
        if max_results and max_results < 5:
            msg = (_('Value ( %s ) for parameter maxResults is invalid. '
                     'Expecting a value greater than 5.') % max_results)
            raise exception.InvalidParameterValue(msg)

        self.context = context
        self.ids = ids
        self.items = self.get_db_items()
        formatted_items = []

        for item in self.items:
            formatted_item = self.format(item)
            self.post_format(formatted_item, item)
            if (formatted_item and
                    not self.filtered_out(formatted_item, filter)):
                formatted_items.append(formatted_item)

        return self.get_paged(formatted_items, max_results, next_token)
Example #55
0
def describe_volumes(context,
                     volume_id=None,
                     filter=None,
                     max_results=None,
                     next_token=None):
    if volume_id and max_results:
        msg = _('The parameter volumeSet cannot be used with the parameter '
                'maxResults')
        raise exception.InvalidParameterCombination(msg)

    volume_describer = VolumeDescriber()
    formatted_volumes = volume_describer.describe(context,
                                                  ids=volume_id,
                                                  filter=filter,
                                                  max_results=max_results,
                                                  next_token=next_token)
    result = {'volumeSet': formatted_volumes}
    if volume_describer.next_token:
        result['nextToken'] = volume_describer.next_token
    return result
Example #56
0
def unassign_private_ip_addresses(context, network_interface_id,
                                  private_ip_address):
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    if network_interface['private_ip_address'] in private_ip_address:
        raise exception.InvalidParameterValue(
                value=str(network_interface['private_ip_address']),
                parameter='PrivateIpAddresses',
                reason='Primary IP address cannot be unassigned')
    neutron = clients.neutron(context)
    os_port = neutron.show_port(network_interface['os_id'])['port']
    fixed_ips = os_port['fixed_ips'] or []
    new_fixed_ips = [ip for ip in fixed_ips
                     if ip['ip_address'] not in private_ip_address]
    if len(new_fixed_ips) + len(private_ip_address) != len(fixed_ips):
        msg = _('Some of the specified addresses are not assigned to '
                'interface %(id)s') % {'id': network_interface_id}
        raise exception.InvalidParameterValue(msg)
    os_port = neutron.update_port(os_port['id'],
                                  {'port': {'fixed_ips': new_fixed_ips}})
    return True
Example #57
0
    def __call__(self, req):
        non_args = [
            'Action', 'Signature', 'AWSAccessKeyId', 'SignatureMethod',
            'SignatureVersion', 'Version', 'Timestamp'
        ]
        args = dict(req.params)
        try:
            expired = ec2utils.is_ec2_timestamp_expired(
                req.params, expires=CONF.ec2_timestamp_expiry)
            if expired:
                msg = _("Timestamp failed validation.")
                LOG.exception(msg)
                raise webob.exc.HTTPForbidden(explanation=msg)

            # Raise KeyError if omitted
            action = req.params['Action']
            # Fix bug lp:720157 for older (version 1) clients
            version = req.params.get('SignatureVersion')
            if version and int(version) == 1:
                non_args.remove('SignatureMethod')
                if 'SignatureMethod' in args:
                    args.pop('SignatureMethod')
            for non_arg in non_args:
                args.pop(non_arg, None)
        except KeyError:
            raise webob.exc.HTTPBadRequest()
        except exception.InvalidRequest as err:
            raise webob.exc.HTTPBadRequest(explanation=err.format_message())

        LOG.debug('action: %s', action)
        for key, value in args.items():
            LOG.debug('arg: %(key)s\t\tval: %(value)s', {
                'key': key,
                'value': value
            })

        # Success!
        api_request = apirequest.APIRequest(action, req.params['Version'],
                                            args)
        req.environ['ec2.request'] = api_request
        return self.application
Example #58
0
def delete_network_interface(context, network_interface_id):
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    if 'instance_id' in network_interface:
        msg = _("Network interface '%(eni_id)s' is currently in use.")
        msg = msg % {'eni_id': network_interface_id}
        raise exception.InvalidParameterValue(msg)

    for address in db_api.get_items(context, 'eipalloc'):
        if address.get('network_interface_id') == network_interface['id']:
            address_api._disassociate_address_item(context, address)

    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, network_interface['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'eni',
                           network_interface)
        try:
            neutron.delete_port(network_interface['os_id'])
        except neutron_exception.PortNotFoundClient:
            pass
    return True
Example #59
0
    def _validate_signature(self, signature, requester_id, requester_ip):
        expected_signature = hmac.new(
            CONF.metadata.metadata_proxy_shared_secret.encode("utf-8"),
            requester_id.encode(), hashlib.sha256).hexdigest()

        if not (signature and utils.constant_time_compare(
                expected_signature, signature)):
            LOG.warning(
                'X-Instance-ID-Signature: %(signature)s does '
                'not match the expected value: '
                '%(expected_signature)s for id: '
                '%(requester_id)s. Request From: '
                '%(requester_ip)s', {
                    'signature': signature,
                    'expected_signature': expected_signature,
                    'requester_id': requester_id,
                    'requester_ip': requester_ip
                })

            msg = _('Invalid proxy request signature.')
            raise webob.exc.HTTPForbidden(explanation=msg)
Example #60
0
def replace_route_table_association(context, association_id, route_table_id):
    route_table = ec2utils.get_db_item(context, route_table_id)
    if route_table['vpc_id'] == ec2utils.change_ec2_id_kind(
            association_id, 'vpc'):
        vpc = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'vpc'))
        if vpc is None:
            raise exception.InvalidAssociationIDNotFound(id=association_id)

        rollback_route_table_id = vpc['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_vpc_item(context, vpc, route_table['id'])
            cleaner.addCleanup(_associate_vpc_item, context, vpc,
                               rollback_route_table_id)

            _update_routes_in_associated_subnets(
                context, cleaner, route_table, default_associations_only=True)
    else:
        subnet = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'subnet'))
        if subnet is None or 'route_table_id' not in subnet:
            raise exception.InvalidAssociationIDNotFound(id=association_id)
        if subnet['vpc_id'] != route_table['vpc_id']:
            msg = _('Route table association %(rtbassoc_id)s and route table '
                    '%(rtb_id)s belong to different networks')
            msg = msg % {
                'rtbassoc_id': association_id,
                'rtb_id': route_table_id
            }
            raise exception.InvalidParameterValue(msg)

        rollback_route_table_id = subnet['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_subnet_item(context, subnet, route_table['id'])
            cleaner.addCleanup(_associate_subnet_item, context, subnet,
                               rollback_route_table_id)

            _update_subnet_routes(context, cleaner, subnet, route_table)

    return {'newAssociationId': association_id}