Example #1
0
def _get_certs_from_pkcs7_substrate(substrate):
    """Extracts DER-encoded X509 certificates from a PKCS7 ASN1 DER substrate

    :param substrate: The substrate to be processed
    :returns: A list of DER-encoded X509 certificates
    """
    try:
        contentInfo, _ = der_decoder.decode(substrate,
                                            asn1Spec=rfc2315.ContentInfo())
        contentType = contentInfo.getComponentByName('contentType')
    except Exception:
        LOG.exception(_LE('Unreadable Certificate.'))
        raise exceptions.UnreadableCert
    if contentType != rfc2315.signedData:
        LOG.exception(_LE('Unreadable Certificate.'))
        raise exceptions.UnreadableCert

    try:
        content, _ = der_decoder.decode(
            contentInfo.getComponentByName('content'),
            asn1Spec=rfc2315.SignedData())
    except Exception:
        LOG.exception(_LE('Unreadable Certificate.'))
        raise exceptions.UnreadableCert

    for cert in content.getComponentByName('certificates'):
        yield der_encoder.encode(cert)
    def unplug_network(self, compute_id, network_id, ip_address=None):
        interfaces = self.get_plugged_networks(compute_id)
        if not interfaces:
            msg = ('Amphora with compute id {compute_id} does not have any '
                   'plugged networks').format(compute_id=compute_id)
            raise base.AmphoraNotFound(msg)

        unpluggers = self._get_interfaces_to_unplug(interfaces, network_id,
                                                    ip_address=ip_address)
        try:
            for index, unplugger in enumerate(unpluggers):
                self.nova_client.servers.interface_detach(
                    server=compute_id, port_id=unplugger.port_id)
        except Exception:
            message = _LE('Error unplugging amphora {amphora_id} from network '
                          '{network_id}.').format(amphora_id=compute_id,
                                                  network_id=network_id)
            if len(unpluggers) > 1:
                message = _LE('{base} Other interfaces have been successfully '
                              'unplugged: ').format(base=message)
                unpluggeds = unpluggers[:index]
                for unplugged in unpluggeds:
                    message = _LE('{base} neutron port '
                                  '{port_id} ').format(
                                      base=message, port_id=unplugged.port_id)
            else:
                message = _LE('{base} No other networks were '
                              'unplugged.').format(base=message)
            LOG.exception(message)
            raise base.UnplugNetworkException(message)
Example #3
0
    def get_cert(cert_ref, **kwargs):
        """Retrieves the specified cert.

        :param cert_ref: the UUID of the cert to retrieve

        :return: octavia.certificates.common.Cert representation of the
                 certificate data
        :raises CertificateStorageException: if certificate retrieval fails
        """
        LOG.info(_LI(
            "Loading certificate {0} from the local filesystem."
        ).format(cert_ref))

        filename_base = os.path.join(CONF.certificates.storage_path, cert_ref)

        filename_certificate = "{0}.crt".format(filename_base, cert_ref)
        filename_private_key = "{0}.key".format(filename_base, cert_ref)
        filename_intermediates = "{0}.int".format(filename_base, cert_ref)
        filename_pkp = "{0}.pass".format(filename_base, cert_ref)

        cert_data = dict()

        try:
            with open(filename_certificate, 'r') as cert_file:
                cert_data['certificate'] = cert_file.read()
        except IOError:
            LOG.error(_LE(
                "Failed to read certificate for {0}."
            ).format(cert_ref))
            raise exceptions.CertificateStorageException(
                msg="Certificate could not be read."
            )
        try:
            with open(filename_private_key, 'r') as key_file:
                cert_data['private_key'] = key_file.read()
        except IOError:
            LOG.error(_LE(
                "Failed to read private key for {0}."
            ).format(cert_ref))
            raise exceptions.CertificateStorageException(
                msg="Private Key could not be read."
            )

        try:
            with open(filename_intermediates, 'r') as int_file:
                cert_data['intermediates'] = int_file.read()
        except IOError:
            pass

        try:
            with open(filename_pkp, 'r') as pass_file:
                cert_data['private_key_passphrase'] = pass_file.read()
        except IOError:
            pass

        return local_common.LocalCert(**cert_data)
    def unplug_vip(self, load_balancer, vip):
        try:
            subnet = self.get_subnet(vip.subnet_id)
        except base.SubnetNotFound:
            msg = _LE("Can't unplug vip because vip subnet {0} was not "
                      "found").format(vip.subnet_id)
            LOG.exception(msg)
            raise base.PluggedVIPNotFound(msg)
        for amphora in six.moves.filter(
            lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
                load_balancer.amphorae):

            interface = self._get_plugged_interface(amphora.compute_id,
                                                    subnet.network_id)
            if not interface:
                # Thought about raising PluggedVIPNotFound exception but
                # then that wouldn't evaluate all amphorae, so just continue
                LOG.debug(_LI('Cannot get amphora %s interface, skipped'),
                          amphora.compute_id)
                continue
            try:
                self.unplug_network(amphora.compute_id, subnet.network_id)
            except Exception:
                pass
            try:
                aap_update = {'port': {
                    'allowed_address_pairs': []
                }}
                self.neutron_client.update_port(interface.port_id,
                                                aap_update)
            except Exception:
                message = _LE('Error unplugging VIP. Could not clear '
                              'allowed address pairs from port '
                              '{port_id}.').format(port_id=vip.port_id)
                LOG.exception(message)
                raise base.UnplugVIPException(message)

            # Delete the VRRP port if we created it
            try:
                port = self.get_port(amphora.vrrp_port_id)
                if port.name.startswith('octavia-lb-vrrp-'):
                    self.neutron_client.delete_port(amphora.vrrp_port_id)
            except base.PortNotFound:
                pass
            except Exception as e:
                LOG.error(_LE('Failed to delete port.  Resources may still '
                              'be in use for port: %(port)s due to '
                              'error: %s(except)s'),
                          {'port': amphora.vrrp_port_id, 'except': e})
    def plug_port(self, amphora, port):
        plugged_interface = None
        try:
            interface = self.nova_client.servers.interface_attach(
                server=amphora.compute_id, net_id=None,
                fixed_ip=None, port_id=port.id)
            plugged_interface = self._nova_interface_to_octavia_interface(
                amphora.compute_id, interface)
        except nova_client_exceptions.NotFound as e:
            if 'Instance' in e.message:
                raise base.AmphoraNotFound(e.message)
            elif 'Network' in e.message:
                raise base.NetworkNotFound(e.message)
            else:
                raise base.PlugNetworkException(e.message)
        except nova_client_exceptions.Conflict:
            LOG.info(_LI('Port %(portid)s is already plugged, '
                     'skipping') % {'portid': port.id})
            plugged_interface = n_data_models.Interface(
                compute_id=amphora.compute_id,
                network_id=port.network_id,
                port_id=port.id,
                fixed_ips=port.fixed_ips)
        except Exception:
            message = _LE('Error plugging amphora (compute_id: '
                          '{compute_id}) into port '
                          '{port_id}.').format(
                              compute_id=amphora.compute_id,
                              port_id=port.id)
            LOG.exception(message)
            raise base.PlugNetworkException(message)

        return plugged_interface
    def deallocate_vip(self, vip):
        """Delete the vrrp_port (instance port) in case nova didn't

        This can happen if a failover has occurred.
        """
        try:
            for amphora in six.moves.filter(self._filter_amphora,
                                            vip.load_balancer.amphorae):
                self.neutron_client.delete_port(amphora.vrrp_port_id)
        except (neutron_client_exceptions.NotFound,
                neutron_client_exceptions.PortNotFoundClient):
            LOG.debug('VIP instance port {0} already deleted.  '
                      'Skipping.'.format(amphora.vrrp_port_id))

        try:
            port = self.get_port(vip.port_id)
        except base.PortNotFound:
            msg = ("Can't deallocate VIP because the vip port {0} cannot be "
                   "found in neutron".format(vip.port_id))
            raise base.VIPConfigurationNotFound(msg)

        self._delete_security_group(vip, port)

        if port.device_owner == OCTAVIA_OWNER:
            try:
                self.neutron_client.delete_port(vip.port_id)
            except Exception:
                message = _LE('Error deleting VIP port_id {port_id} from '
                              'neutron').format(port_id=vip.port_id)
                LOG.exception(message)
                raise base.DeallocateVIPException(message)
        else:
            LOG.info(_LI("Port %s will not be deleted by Octavia as it was "
                         "not created by Octavia."), vip.port_id)
Example #7
0
    def get_glance_client(cls, region, service_name=None, endpoint=None,
                          endpoint_type='publicURL', insecure=False,
                          cacert=None):
        """Create glance client object.

        :param region: The region of the service
        :param service_name: The name of the glance service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The endpoint_type of the service
        :param insecure: Turn off certificate validation
        :param cacert: CA Cert file path
        :return: a Glance Client object.
        :raises Exception: if the client cannot be created
        """
        if not cls.glance_client:
            kwargs = {'region_name': region,
                      'session': keystone.get_session(),
                      'interface': endpoint_type}
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint'] = endpoint
                if endpoint.startswith("https"):
                    kwargs['insecure'] = insecure
                    kwargs['cacert'] = cacert
            try:
                cls.glance_client = glance_client.Client(
                    GLANCE_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Glance client."))
        return cls.glance_client
    def unplug_vip(self, load_balancer, vip):
        try:
            subnet = self.get_subnet(vip.subnet_id)
        except base.SubnetNotFound:
            msg = ("Can't unplug vip because vip subnet {0} was not "
                   "found").format(vip.subnet_id)
            raise base.PluggedVIPNotFound(msg)
        for amphora in six.moves.filter(
            lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
                load_balancer.amphorae):

            interface = self._get_plugged_interface(amphora.compute_id,
                                                    subnet.network_id)
            if not interface:
                # Thought about raising PluggedVIPNotFound exception but
                # then that wouldn't evaluate all amphorae, so just continue
                continue
            try:
                self.unplug_network(amphora.compute_id, subnet.network_id)
            except Exception:
                pass
            try:
                aap_update = {'port': {
                    'allowed_address_pairs': []
                }}
                self.neutron_client.update_port(interface.port_id,
                                                aap_update)
            except Exception:
                message = _LE('Error unplugging VIP. Could not clear '
                              'allowed address pairs from port '
                              '{port_id}.').format(port_id=vip.port_id)
                LOG.exception(message)
                raise base.UnplugVIPException(message)
    def allocate_vip(self, load_balancer):
        if not load_balancer.vip.port_id and not load_balancer.vip.subnet_id:
            raise base.AllocateVIPException('Cannot allocate a vip '
                                            'without a port_id or '
                                            'a subnet_id.')
        if load_balancer.vip.port_id:
            LOG.info(_LI('Port %s already exists. Nothing to be done.'),
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        # Must retrieve the network_id from the subnet
        subnet = self.get_subnet(load_balancer.vip.subnet_id)

        # It can be assumed that network_id exists
        port = {'port': {'name': 'octavia-lb-' + load_balancer.id,
                         'network_id': subnet.network_id,
                         'admin_state_up': False,
                         'device_id': 'lb-{0}'.format(load_balancer.id),
                         'device_owner': OCTAVIA_OWNER}}
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception:
            message = _LE('Error creating neutron port on network '
                          '{network_id}.').format(
                network_id=subnet.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(message)
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Example #10
0
    def _actually_delete_cert(cert_ref):
        """Deletes the specified cert. Very dangerous. Do not recommend.

        :param cert_ref: the UUID of the cert to delete
        :raises Exception: if certificate deletion fails
        """
        connection = barbican_common.BarbicanAuth.get_barbican_client()

        LOG.info(_LI(
            "Recursively deleting certificate container {0} from Barbican."
        ).format(cert_ref))
        try:
            certificate_container = connection.containers.get(cert_ref)
            certificate_container.certificate.delete()
            if certificate_container.intermediates:
                certificate_container.intermediates.delete()
            if certificate_container.private_key_passphrase:
                certificate_container.private_key_passphrase.delete()
            certificate_container.private_key.delete()
            certificate_container.delete()
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE(
                    "Error recursively deleting container {0}: {1}"
                ).format(cert_ref, str(e)))
Example #11
0
    def get_cert(cert_ref, resource_ref=None, check_only=False,
                 service_name='Octavia'):
        """Retrieves the specified cert and registers as a consumer.

        :param cert_ref: the UUID of the cert to retrieve
        :param resource_ref: Full HATEOAS reference to the consuming resource
        :param check_only: Read Certificate data without registering
        :param service_name: Friendly name for the consuming service

        :return: octavia.certificates.common.Cert representation of the
                 certificate data
        :raises Exception: if certificate retrieval fails
        """
        connection = barbican_common.BarbicanAuth.get_barbican_client()

        LOG.info(_LI(
            "Loading certificate container {0} from Barbican."
        ).format(cert_ref))
        try:
            if check_only:
                cert_container = connection.containers.get(
                    container_ref=cert_ref
                )
            else:
                cert_container = connection.containers.register_consumer(
                    container_ref=cert_ref,
                    name=service_name,
                    url=resource_ref
                )
            return barbican_common.BarbicanCert(cert_container)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE(
                    "Error getting {0}: {1}"
                ).format(cert_ref, str(e)))
Example #12
0
    def delete_cert(cert_ref, resource_ref=None, service_name='Octavia'):
        """Deregister as a consumer for the specified cert.

        :param cert_ref: the UUID of the cert to retrieve
        :param resource_ref: Full HATEOAS reference to the consuming resource
        :param service_name: Friendly name for the consuming service

        :raises Exception: if deregistration fails
        """
        connection = barbican_common.BarbicanAuth.get_barbican_client()

        LOG.info(_LI(
            "Deregistering as a consumer of {0} in Barbican."
        ).format(cert_ref))
        try:
            connection.containers.remove_consumer(
                container_ref=cert_ref,
                name=service_name,
                url=resource_ref
            )
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE(
                    "Error deregistering as a consumer of {0}: {1}"
                ).format(cert_ref, str(e)))
Example #13
0
    def get_create_load_balancer_flow(self, topology):
        """Creates a conditional graph flow that allocates a loadbalancer to

        two spare amphorae.
        :raises InvalidTopology: Invalid topology specified
        :return: The graph flow for creating an active_standby loadbalancer.
        """

        f_name = constants.CREATE_LOADBALANCER_FLOW
        lb_create_flow = unordered_flow.Flow(f_name)

        if topology == constants.TOPOLOGY_ACTIVE_STANDBY:
            master_amp_sf = self.amp_flows.get_amphora_for_lb_subflow(
                prefix=constants.ROLE_MASTER, role=constants.ROLE_MASTER)
            backup_amp_sf = self.amp_flows.get_amphora_for_lb_subflow(
                prefix=constants.ROLE_BACKUP, role=constants.ROLE_BACKUP)
            lb_create_flow.add(master_amp_sf, backup_amp_sf)
        elif topology == constants.TOPOLOGY_SINGLE:
            amphora_sf = self.amp_flows.get_amphora_for_lb_subflow(
                prefix=constants.ROLE_STANDALONE,
                role=constants.ROLE_STANDALONE)
            lb_create_flow.add(amphora_sf)
        else:
            LOG.error(_LE("Unknown topology: %s.  Unable to build load "
                          "balancer."), topology)
            raise exceptions.InvalidTopology(topology=topology)

        return lb_create_flow
Example #14
0
    def get_nova_client(cls, region, service_name=None, endpoint=None,
                        endpoint_type='publicURL', insecure=False,
                        cacert=None):
        """Create nova client object.

        :param region: The region of the service
        :param service_name: The name of the nova service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The type of the endpoint
        :param insecure: Turn off certificate validation
        :param cacert: CA Cert file path
        :return: a Nova Client object.
        :raises Exception: if the client cannot be created
        """
        if not cls.nova_client:
            kwargs = {'region_name': region,
                      'session': keystone.get_session(),
                      'endpoint_type': endpoint_type,
                      'insecure': insecure}
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint_override'] = endpoint
            if cacert:
                kwargs['cacert'] = cacert
            try:
                cls.nova_client = nova_client.Client(
                    NOVA_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Nova client."))
        return cls.nova_client
Example #15
0
    def execute(self, deltas):
        """Handle network plugging based off deltas."""

        added_ports = {}
        for amp_id, delta in six.iteritems(deltas):
            added_ports[amp_id] = []
            for nic in delta.add_nics:
                interface = self.network_driver.plug_network(delta.compute_id,
                                                             nic.network_id)
                port = self.network_driver.get_port(interface.port_id)
                port.network = self.network_driver.get_network(port.network_id)
                for fixed_ip in port.fixed_ips:
                    fixed_ip.subnet = self.network_driver.get_subnet(
                        fixed_ip.subnet_id)
                added_ports[amp_id].append(port)
            for nic in delta.delete_nics:
                try:
                    self.network_driver.unplug_network(delta.compute_id,
                                                       nic.network_id)
                except base.NetworkNotFound:
                    LOG.debug("Network %d not found ", nic.network_id)
                except Exception as e:
                    LOG.error(
                        _LE("Unable to unplug network - exception: %s"), e)
        return added_ports
Example #16
0
    def get_neutron_client(cls, region, service_name=None, endpoint=None,
                           endpoint_type='publicURL'):
        """Create neutron client object.

        :param region: The region of the service
        :param service_name: The name of the neutron service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The endpoint_type of the service
        :return: a Neutron Client object.
        :raises Exception: if the client cannot be created
        """
        if not cls.neutron_client:
            kwargs = {'region_name': region,
                      'session': keystone.get_session(),
                      'endpoint_type': endpoint_type}
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint_override'] = endpoint
            try:
                cls.neutron_client = neutron_client.Client(
                    NEUTRON_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Neutron client."))
        return cls.neutron_client
Example #17
0
 def get_subnet(self, subnet_id):
     try:
         subnet = self.neutron_client.show_subnet(subnet_id)
         return utils.convert_subnet_dict_to_model(subnet)
     except neutron_client_exceptions.NotFound:
         message = _LE('Subnet not found '
                       '(subnet id: {subnet_id}.').format(
             subnet_id=subnet_id)
         LOG.exception(message)
         raise base.SubnetNotFound(message)
     except Exception:
         message = _LE('Error retrieving subnet '
                       '(subnet id: {subnet_id}.').format(
             subnet_id=subnet_id)
         LOG.exception(message)
         raise base.NetworkException(message)
Example #18
0
 def deallocate_vip(self, vip):
     try:
         port = self.get_port(vip.port_id)
     except base.PortNotFound:
         msg = ("Can't deallocate VIP because the vip port {0} cannot be "
                "found in neutron".format(vip.port_id))
         raise base.VIPConfigurationNotFound(msg)
     if port.device_owner != OCTAVIA_OWNER:
         LOG.info(_LI("Port %s will not be deleted by Octavia as it was "
                      "not created by Octavia."), vip.port_id)
         if self.sec_grp_enabled:
             sec_grp = self._get_lb_security_group(vip.load_balancer.id)
             sec_grp = sec_grp.get('id')
             LOG.info(
                 _LI("Removing security group %(sg)s from port %(port)s"),
                 {'sg': sec_grp, 'port': vip.port_id})
             raw_port = self.neutron_client.show_port(port.id)
             sec_grps = raw_port.get('port', {}).get('security_groups', [])
             if sec_grp in sec_grps:
                 sec_grps.remove(sec_grp)
             port_update = {'port': {'security_groups': sec_grps}}
             self.neutron_client.update_port(port.id, port_update)
             self._delete_vip_security_group(sec_grp)
         return
     try:
         self.neutron_client.delete_port(vip.port_id)
     except Exception:
         message = _LE('Error deleting VIP port_id {port_id} from '
                       'neutron').format(port_id=vip.port_id)
         LOG.exception(message)
         raise base.DeallocateVIPException(message)
     if self.sec_grp_enabled:
         sec_grp = self._get_lb_security_group(vip.load_balancer.id)
         sec_grp = sec_grp.get('id')
         self._delete_vip_security_group(sec_grp)
Example #19
0
    def get_glance_client(cls, region, service_name=None, endpoint=None,
                          endpoint_type='publicURL'):
        """Create glance client object.

        :param region: The region of the service
        :param service_name: The name of the glance service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The endpoint_type of the service
        :return: a Glance Client object.
        :raises Exception: if the client cannot be created
        """
        if not cls.glance_client:
            kwargs = {'region_name': region,
                      'session': keystone.get_session(),
                      'interface': endpoint_type}
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint'] = endpoint
            try:
                cls.glance_client = glance_client.Client(
                    GLANCE_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Glance client."))
        return cls.glance_client
Example #20
0
 def get_port(self, port_id):
     try:
         port = self.neutron_client.show_port(port_id)
         return utils.convert_port_dict_to_model(port)
     except neutron_client_exceptions.NotFound:
         message = _LE('Port not found '
                       '(port id: {port_id}.').format(
             port_id=port_id)
         LOG.exception(message)
         raise base.PortNotFound(message)
     except Exception:
         message = _LE('Error retrieving port '
                       '(port id: {port_id}.').format(
             port_id=port_id)
         LOG.exception(message)
         raise base.NetworkException(message)
Example #21
0
def get_host_names(certificate):
    """Extract the host names from the Pem encoded X509 certificate

    :param certificate: A PEM encoded certificate
    :returns: A dictionary containing the following keys:
    ['cn', 'dns_names']
    where 'cn' is the CN from the SubjectName of the certificate, and
    'dns_names' is a list of dNSNames (possibly empty) from
    the SubjectAltNames of the certificate.
    """
    try:
        certificate = certificate.encode("ascii")

        cert = x509.load_pem_x509_certificate(certificate, backends.default_backend())
        cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0]
        host_names = {"cn": cn.value.lower(), "dns_names": []}
        try:
            ext = cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_ALTERNATIVE_NAME)
            host_names["dns_names"] = ext.value.get_values_for_type(x509.DNSName)
        except x509.ExtensionNotFound:
            LOG.debug("%s extension not found", x509.OID_SUBJECT_ALTERNATIVE_NAME)

        return host_names
    except Exception:
        LOG.exception(_LE("Unreadable certificate."))
        raise exceptions.UnreadableCert
Example #22
0
    def delete_cert(project_id, cert_ref, **kwargs):
        """Deletes the specified cert.

        :param project_id: Ignored in this implementation
        :param cert_ref: the UUID of the cert to delete

        :raises CertificateStorageException: if certificate deletion fails
        """
        LOG.info(_LI("Deleting certificate %s from the local filesystem."),
                 cert_ref)

        filename_base = os.path.join(CONF.certificates.storage_path, cert_ref)

        filename_certificate = "{0}.crt".format(filename_base)
        filename_private_key = "{0}.key".format(filename_base)
        filename_intermediates = "{0}.int".format(filename_base)
        filename_pkp = "{0}.pass".format(filename_base)

        try:
            os.remove(filename_certificate)
            os.remove(filename_private_key)
            os.remove(filename_intermediates)
            os.remove(filename_pkp)
        except IOError as ioe:
            LOG.error(_LE("Failed to delete certificate %s"), cert_ref)
            raise exceptions.CertificateStorageException(message=ioe.message)
    def _delete_vip_security_group(self, sec_grp):
        """Deletes a security group in neutron.

        Retries upon an exception because removing a security group from
        a neutron port does not happen immediately.
        """
        attempts = 0
        while attempts <= CONF.networking.max_retries:
            try:
                self.neutron_client.delete_security_group(sec_grp)
                LOG.info(_LI("Deleted security group %s"), sec_grp)
                return
            except neutron_client_exceptions.NotFound:
                LOG.info(_LI("Security group %s not found, will assume it is "
                             "already deleted"), sec_grp)
                return
            except Exception:
                LOG.warning(_LW("Attempt %(attempt)s to remove security group "
                                "%(sg)s failed."),
                            {'attempt': attempts + 1, 'sg': sec_grp})
            attempts += 1
            time.sleep(CONF.networking.retry_interval)
        message = _LE("All attempts to remove security group {0} have "
                      "failed.").format(sec_grp)
        LOG.exception(message)
        raise base.DeallocateVIPException(message)
Example #24
0
    def failover_amphora(self, amphora_id):
        """Perform failover operations for an amphora.

        :param amphora_id: ID for amphora to failover
        :returns: None
        :raises AmphoraNotFound: The referenced amphora was not found
        """

        try:
            amp = self._amphora_repo.get(db_apis.get_session(),
                                         id=amphora_id)

            failover_amphora_tf = self._taskflow_load(
                self._amphora_flows.get_failover_flow(role=amp.role),
                store={constants.FAILED_AMPHORA: amp,
                       constants.LOADBALANCER_ID: amp.load_balancer_id})
            with tf_logging.DynamicLoggingListener(
                    failover_amphora_tf, log=LOG,
                    hide_inputs_outputs_of=self._exclude_result_logging_tasks):

                failover_amphora_tf.run()

        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Failover exception: %s") % e)
Example #25
0
 def get_network(self, network_id):
     try:
         network = self.neutron_client.show_network(network_id)
         return utils.convert_network_dict_to_model(network)
     except neutron_client_exceptions.NotFound:
         message = _LE('Network not found '
                       '(network id: {network_id}.').format(
             network_id=network_id)
         LOG.exception(message)
         raise base.NetworkNotFound(message)
     except Exception:
         message = _LE('Error retrieving network '
                       '(network id: {network_id}.').format(
             network_id=network_id)
         LOG.exception(message)
         raise base.NetworkException(message)
Example #26
0
 def __init__(self, cert_container):
     if not isinstance(cert_container,
                       barbican_client.containers.CertificateContainer):
         raise TypeError(_LE(
             "Retrieved Barbican Container is not of the correct type "
             "(certificate)."))
     self._cert_container = cert_container
Example #27
0
    def execute(self, amphora_id, ports=None, config_drive_files=None):
        """Create an amphora

        :returns: an amphora
        """
        ports = ports or []
        config_drive_files = config_drive_files or {}
        LOG.debug("Compute create execute for amphora with id %s", amphora_id)

        ssh_access = CONF.controller_worker.amp_ssh_access_allowed
        ssh_key = CONF.controller_worker.amp_ssh_key_name
        key_name = None if not ssh_access else ssh_key

        try:
            agent_cfg = agent_jinja_cfg.AgentJinjaTemplater()
            config_drive_files['/etc/octavia/amphora-agent.conf'] = (
                agent_cfg.build_agent_config(amphora_id))
            compute_id = self.compute.build(
                name="amphora-" + amphora_id,
                amphora_flavor=CONF.controller_worker.amp_flavor_id,
                image_id=CONF.controller_worker.amp_image_id,
                key_name=key_name,
                sec_groups=CONF.controller_worker.amp_secgroup_list,
                network_ids=[CONF.controller_worker.amp_network],
                port_ids=[port.id for port in ports],
                config_drive_files=config_drive_files)

            LOG.debug("Server created with id: %s for amphora id: %s",
                      compute_id, amphora_id)
            return compute_id

        except Exception:
            LOG.exception(_LE("Compute create for amphora id: %s failed"),
                          amphora_id)
            raise
Example #28
0
    def execute(self, amphora_id, ports=None, config_drive_files=None):
        """Create an amphora

        :returns: an amphora
        """
        ports = ports or []
        config_drive_files = config_drive_files or {}
        LOG.debug("Nova Create execute for amphora with id %s"
                  % amphora_id)

        try:
            agent_cfg = agent_jinja_cfg.AgentJinjaTemplater()
            config_drive_files['/etc/octavia/amphora-agent.conf'] = (
                agent_cfg.build_agent_config(amphora_id))
            compute_id = self.compute.build(
                name="amphora-" + amphora_id,
                amphora_flavor=CONF.controller_worker.amp_flavor_id,
                image_id=CONF.controller_worker.amp_image_id,
                key_name=CONF.controller_worker.amp_ssh_key_name,
                sec_groups=CONF.controller_worker.amp_secgroup_list,
                network_ids=[CONF.controller_worker.amp_network],
                port_ids=[port.id for port in ports],
                config_drive_files=config_drive_files)

            LOG.debug("Server created with id: %s for amphora id: %s" %
                      (compute_id, amphora_id))
            return compute_id

        except Exception as e:
            LOG.error(_LE("Nova create for amphora id: %(amp)s "
                          "failed: %(exp)s"),
                      {'amp': amphora_id, 'exp': e})
            raise e
Example #29
0
    def sign_cert(cls, csr, validity=None, **kwargs):
        """Signs a certificate using Anchor based on the specified CSR

        :param csr: A Certificate Signing Request
        :param validity: Will be ignored for now
        :param kwargs: Will be ignored for now

        :return: Signed certificate
        :raises Exception: if certificate signing fails
        """
        LOG.debug("Signing a certificate request using Anchor")

        try:
            LOG.debug('Certificate: %s', csr)
            r = requests.post(CONF.anchor.url, data={
                'user': CONF.anchor.username,
                'secret': CONF.anchor.password,
                'encoding': 'pem',
                'csr': csr})

            if r.status_code != 200:
                LOG.debug('Anchor returned: %s', r.content)
                raise AnchorException("Anchor returned Status Code : "
                                      + str(r.status_code))

            return r.content

        except Exception as e:
            LOG.error(_LE("Unable to sign certificate."))
            raise exceptions.CertificateGenerationException(msg=e)
Example #30
0
    def build(
        self,
        name="amphora_name",
        amphora_flavor=None,
        image_id=None,
        key_name=None,
        sec_groups=None,
        network_ids=None,
        port_ids=None,
        config_drive_files=None,
        user_data=None,
    ):
        """Create a new virtual machine.

        :param name: optional name for amphora
        :param amphora_flavor: image flavor for virtual machine
        :param image_id: image ID for virtual machine
        :param key_name: keypair to add to the virtual machine
        :param sec_groups: Security group IDs for virtual machine
        :param network_ids: Network IDs to include on virtual machine
        :param port_ids: Port IDs to include on virtual machine
        :param config_drive_files:  An optional dict of files to overwrite on
        the server upon boot. Keys are file names (i.e. /etc/passwd)
        and values are the file contents (either as a string or as
        a file-like object). A maximum of five entries is allowed,
        and each file must be 10k or less.
        :param user_data: Optional user data to pass to be exposed by the
        metadata server this can be a file type object as well or
        a string

        :raises NovaBuildException: if nova failed to build virtual machine
        :returns: UUID of amphora
        """

        try:
            network_ids = network_ids or []
            port_ids = port_ids or []
            nics = []
            if network_ids:
                nics.extend([{"net-id": net_id} for net_id in network_ids])
            if port_ids:
                nics.extend([{"port-id": port_id} for port_id in port_ids])

            amphora = self.manager.create(
                name=name,
                image=image_id,
                flavor=amphora_flavor,
                key_name=key_name,
                security_groups=sec_groups,
                nics=nics,
                files=config_drive_files,
                userdata=user_data,
                config_drive=True,
            )

            return amphora.id
        except Exception:
            LOG.exception(_LE("Error building nova virtual machine."))
            raise exceptions.ComputeBuildException()
Example #31
0
    def mark_amphora_status_error(self, amphora_id):
        """Sets an amphora status to ERROR.

        NOTE: This should only be called from revert methods.

        :param amphora_id: Amphora ID to set the status to ERROR
        """
        try:
            self.amphora_repo.update(db_apis.get_session(),
                                     id=amphora_id,
                                     status=constants.ERROR)
        except Exception as e:
            LOG.error(
                _LE("Failed to update amphora %(amp)s "
                    "status to ERROR due to: "
                    "%(except)s"), {
                        'amp': amphora_id,
                        'except': e
                    })
Example #32
0
    def mark_health_mon_prov_status_error(self, health_mon_id):
        """Sets a health monitor provisioning status to ERROR.

        NOTE: This should only be called from revert methods.

        :param health_mon_id: Health Monitor ID to set prov status to ERROR
        """
        try:
            self.health_mon_repo.update(db_apis.get_session(),
                                        pool_id=health_mon_id,
                                        provisioning_status=constants.ERROR)
        except Exception as e:
            LOG.error(
                _LE("Failed to update health monitor %(health)s "
                    "provisioning status to ERROR due to: "
                    "%(except)s"), {
                        'health': health_mon_id,
                        'except': e
                    })
Example #33
0
    def mark_l7rule_prov_status_error(self, l7rule_id):
        """Sets a L7 rule provisioning status to ERROR.

        NOTE: This should only be called from revert methods.

        :param l7rule_id: L7 Rule ID to set provisioning status to ERROR
        """
        try:
            self.l7rule_repo.update(db_apis.get_session(),
                                    id=l7rule_id,
                                    provisioning_status=constants.ERROR)
        except Exception as e:
            LOG.error(
                _LE("Failed to update l7rule %(l7r)s "
                    "provisioning status to ERROR due to: "
                    "%(except)s"), {
                        'l7r': l7rule_id,
                        'except': e
                    })
Example #34
0
    def mark_pool_prov_status_error(self, pool_id):
        """Sets a pool provisioning status to ERROR.

        NOTE: This should only be called from revert methods.

        :param pool_id: Pool ID to set provisioning status to ERROR
        """
        try:
            self.pool_repo.update(db_apis.get_session(),
                                  id=pool_id,
                                  provisioning_status=constants.ERROR)
        except Exception as e:
            LOG.error(
                _LE("Failed to update pool %(pool)s "
                    "provisioning status to ERROR due to: "
                    "%(except)s"), {
                        'pool': pool_id,
                        'except': e
                    })
Example #35
0
    def mark_listener_prov_status_error(self, listener_id):
        """Sets a listener provisioning status to ERROR.

        NOTE: This should only be called from revert methods.

        :param listener_id: Listener ID to set provisioning status to ERROR
        """
        try:
            self.listener_repo.update(db_apis.get_session(),
                                      id=listener_id,
                                      provisioning_status=constants.ERROR)
        except Exception as e:
            LOG.error(
                _LE("Failed to update listener %(list)s "
                    "provisioning status to ERROR due to: "
                    "%(except)s"), {
                        'list': listener_id,
                        'except': e
                    })
Example #36
0
def _parse_pkcs7_bundle(pkcs7):
    """Parse a PKCS7 certificate bundle in DER or PEM format

    :param pkcs7: A pkcs7 bundle in DER or PEM format
    :returns: A list of individual DER-encoded certificates
    """
    # Look for PEM encoding
    if PKCS7_BEG in pkcs7:
        try:
            for substrate in _read_pem_blocks(pkcs7):
                for cert in _get_certs_from_pkcs7_substrate(substrate):
                    yield cert
        except Exception:
            LOG.exception(_LE('Unreadable Certificate.'))
            raise exceptions.UnreadableCert

    # If no PEM encoding, assume this is DER encoded and try to decode
    else:
        for cert in _get_certs_from_pkcs7_substrate(pkcs7):
            yield cert
Example #37
0
    def mark_loadbalancer_prov_status_active(self, loadbalancer_id):
        """Sets a load balancer provisioning status to ACTIVE.

        NOTE: This should only be called from revert methods.

        :param loadbalancer_id: Load balancer ID to set provisioning
                                status to ACTIVE
        """
        try:
            self.loadbalancer_repo.update(db_apis.get_session(),
                                          id=loadbalancer_id,
                                          provisioning_status=constants.ACTIVE)
        except Exception as e:
            LOG.error(
                _LE("Failed to update load balancer %(lb)s "
                    "provisioning status to ACTIVE due to: "
                    "%(except)s"), {
                        'lb': loadbalancer_id,
                        'except': e
                    })
Example #38
0
def get_session():
    """Initializes a Keystone session.

    :return: a Keystone Session object
    :raises Exception: if the session cannot be established
    """
    global _SESSION
    if not _SESSION:

        kwargs = {
            'auth_url': cfg.CONF.keystone_authtoken.auth_uri,
            'username': cfg.CONF.keystone_authtoken.admin_user,
            'password': cfg.CONF.keystone_authtoken.admin_password
        }

        if cfg.CONF.keystone_authtoken.auth_version == '2':
            client = v2_client
            kwargs['tenant_name'] = (
                cfg.CONF.keystone_authtoken.admin_tenant_name)
        elif cfg.CONF.keystone_authtoken.auth_version == '3':
            client = v3_client
            kwargs['project_name'] = (
                cfg.CONF.keystone_authtoken.admin_tenant_name)
            kwargs['user_domain_name'] = (
                cfg.CONF.keystone_authtoken_v3.admin_user_domain)
            kwargs['project_domain_name'] = (
                cfg.CONF.keystone_authtoken_v3.admin_project_domain)
        else:
            raise Exception('Unknown keystone version!')

        try:
            kc = client.Password(**kwargs)
            _SESSION = session.Session(
                auth=kc,
                verify=(cfg.CONF.keystone_authtoken.cafile
                        or not cfg.CONF.keystone_authtoken.insecure))
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception(_LE("Error creating Keystone session."))

    return _SESSION
Example #39
0
    def _translate_amphora(self, nova_response):
        '''Convert a nova virtual machine into an amphora object.

        :param nova_response: JSON response from nova
        :returns: an amphora object
        '''
        # Extract interfaces of virtual machine to populate desired amphora
        # fields

        lb_network_ip = None

        try:
            inf_list = nova_response.interface_list()
            for interface in inf_list:
                if (getattr(interface, 'net_id') ==
                        CONF.controller_worker.amp_network):
                    lb_network_ip = getattr(
                        interface, 'fixed_ips')[0]['ip_address']
                    break
        except Exception:
            LOG.debug('Extracting virtual interfaces through nova '
                      'os-interfaces extension failed.')

        if not lb_network_ip:
            # Try os-networks extension
            # TODO(bharath) Remove when RAX doesn't need that any longer
            try:
                net_name = self._nova_client.networks.get(
                    CONF.controller_worker.amp_network).label
                if net_name in nova_response.addresses:
                    lb_network_ip = nova_response.addresses[
                        net_name][0]['addr']
            except Exception:
                LOG.exception(_LE('Error retrieving nova virtual interfaces'))

        response = models.Amphora(
            compute_id=getattr(nova_response, 'id'),
            status=getattr(nova_response, 'status'),
            lb_network_ip=lb_network_ip
        )
        return response
    def revert(self, result, loadbalancer, *args, **kwargs):
        """Handle a failed amphora vip plug notification."""
        if isinstance(result, failure.Failure):
            return
        LOG.warning(_LW("Reverting Get Amphora VRRP Interface."))
        for amp in six.moves.filter(
                lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
                loadbalancer.amphorae):

            try:
                self.amphora_repo.update(db_apis.get_session(),
                                         amp.id,
                                         vrrp_interface=None)
            except Exception as e:
                LOG.error(
                    _LE("Failed to update amphora %(amp)s "
                        "VRRP interface to None due to: "
                        "%(except)s"), {
                            'amp': amp.id,
                            'except': e
                        })
    def plug_network(self, compute_id, network_id, ip_address=None):
        try:
            interface = self.nova_client.servers.interface_attach(
                server=compute_id, net_id=network_id, fixed_ip=ip_address,
                port_id=None)
        except nova_client_exceptions.NotFound as e:
            if 'Instance' in e.message:
                raise base.AmphoraNotFound(e.message)
            elif 'Network' in e.message:
                raise base.NetworkNotFound(e.message)
            else:
                raise base.PlugNetworkException(e.message)
        except Exception:
            message = _LE('Error plugging amphora (compute_id: {compute_id}) '
                          'into network {network_id}.').format(
                              compute_id=compute_id,
                              network_id=network_id)
            LOG.exception(message)
            raise base.PlugNetworkException(message)

        return self._nova_interface_to_octavia_interface(compute_id, interface)
Example #42
0
    def failover_amphora(self, amphora_id):
        """Perform failover operations for an amphora.

        :param amphora_id: ID for amphora to failover
        :returns: None
        :raises AmphoraNotFound: The referenced amphora was not found
        """

        try:
            amp = self._amphora_repo.get(db_apis.get_session(),
                                         id=amphora_id)
            stored_params = {constants.FAILED_AMPHORA: amp,
                             constants.LOADBALANCER_ID: amp.load_balancer_id,
                             constants.BUILD_TYPE_PRIORITY:
                                 constants.LB_CREATE_FAILOVER_PRIORITY}

            # if we run with anti-affinity we need to set the server group
            # as well
            if CONF.nova.enable_anti_affinity:
                lb = self._amphora_repo.get_all_lbs_on_amphora(
                    db_apis.get_session(), amp.id)
                if lb:
                    stored_params[constants.SERVER_GROUP_ID] = (
                        lb[0].server_group_id)

            failover_amphora_tf = self._taskflow_load(
                self._amphora_flows.get_failover_flow(
                    role=amp.role,
                    status=amp.status),
                store=stored_params)
            with tf_logging.DynamicLoggingListener(
                    failover_amphora_tf, log=LOG,
                    hide_inputs_outputs_of=self._exclude_result_logging_tasks):

                failover_amphora_tf.run()

        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Failover exception: %s") % e)
Example #43
0
 def dosend(self, obj):
     envelope_str = status_message.wrap_envelope(obj, self.key)
     addrinfo = round_robin_addr(self.dests)
     # dest = (family, socktype, proto, canonname, sockaddr)
     # e.g. 0 = sock family, 4 = sockaddr - what we actually need
     if addrinfo is None:
         LOG.error(
             _LE('No controller address found. '
                 'Unable to send heartbeat.'))
         return
     try:
         if addrinfo[0] == socket.AF_INET:
             self.v4sock.sendto(envelope_str, addrinfo[4])
         elif addrinfo[0] == socket.AF_INET6:
             self.v6sock.sendto(envelope_str, addrinfo[4])
     except socket.error:
         # Pass here as on amp boot it will get one or more
         # error: [Errno 101] Network is unreachable
         # while the networks are coming up
         # No harm in trying to send as it will still failover
         # if the message isn't received
         pass
Example #44
0
    def get_neutron_client(cls,
                           region,
                           service_name=None,
                           endpoint=None,
                           endpoint_type='publicURL',
                           insecure=False,
                           ca_cert=None):
        """Create neutron client object.

        :param region: The region of the service
        :param service_name: The name of the neutron service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The endpoint_type of the service
        :param insecure: Turn off certificate validation
        :param ca_cert: CA Cert file path
        :return: a Neutron Client object.
        :raises Exception: if the client cannot be created
        """
        ksession = keystone.KeystoneSession()
        if not cls.neutron_client:
            kwargs = {
                'region_name': region,
                'session': ksession.get_session(),
                'endpoint_type': endpoint_type,
                'insecure': insecure
            }
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint_override'] = endpoint
            if ca_cert:
                kwargs['ca_cert'] = ca_cert
            try:
                cls.neutron_client = neutron_client.Client(
                    NEUTRON_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Neutron client."))
        return cls.neutron_client
Example #45
0
    def get_glance_client(cls,
                          region,
                          service_name=None,
                          endpoint=None,
                          endpoint_type='publicURL',
                          insecure=False,
                          cacert=None):
        """Create glance client object.

        :param region: The region of the service
        :param service_name: The name of the glance service in the catalog
        :param endpoint: The endpoint of the service
        :param endpoint_type: The endpoint_type of the service
        :param insecure: Turn off certificate validation
        :param cacert: CA Cert file path
        :return: a Glance Client object.
        :raises Exception: if the client cannot be created
        """
        ksession = keystone.KeystoneSession()
        if not cls.glance_client:
            kwargs = {
                'region_name': region,
                'session': ksession.get_session(),
                'interface': endpoint_type
            }
            if service_name:
                kwargs['service_name'] = service_name
            if endpoint:
                kwargs['endpoint'] = endpoint
                if endpoint.startswith("https"):
                    kwargs['insecure'] = insecure
                    kwargs['cacert'] = cacert
            try:
                cls.glance_client = glance_client.Client(
                    GLANCE_VERSION, **kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Error creating Glance client."))
        return cls.glance_client
Example #46
0
 def deallocate_vip(self, vip):
     try:
         port = self.get_port(vip.port_id)
     except base.PortNotFound:
         msg = ("Can't deallocate VIP because the vip port {0} cannot be "
                "found in neutron".format(vip.port_id))
         raise base.VIPConfigurationNotFound(msg)
     if port.device_owner != OCTAVIA_OWNER:
         LOG.info(
             _LI("Port %s will not be deleted by Octavia as it was "
                 "not created by Octavia."), vip.port_id)
         if self.sec_grp_enabled:
             sec_grp = self._get_lb_security_group(vip.load_balancer.id)
             sec_grp = sec_grp.get('id')
             LOG.info(
                 _LI("Removing security group %(sg)s from port %(port)s"), {
                     'sg': sec_grp,
                     'port': vip.port_id
                 })
             raw_port = self.neutron_client.show_port(port.id)
             sec_grps = raw_port.get('port', {}).get('security_groups', [])
             if sec_grp in sec_grps:
                 sec_grps.remove(sec_grp)
             port_update = {'port': {'security_groups': sec_grps}}
             self.neutron_client.update_port(port.id, port_update)
             self._delete_vip_security_group(sec_grp)
         return
     try:
         self.neutron_client.delete_port(vip.port_id)
     except Exception:
         message = _LE('Error deleting VIP port_id {port_id} from '
                       'neutron').format(port_id=vip.port_id)
         LOG.exception(message)
         raise base.DeallocateVIPException(message)
     if self.sec_grp_enabled:
         sec_grp = self._get_lb_security_group(vip.load_balancer.id)
         sec_grp = sec_grp.get('id')
         self._delete_vip_security_group(sec_grp)
Example #47
0
    def delete_cert(cert_ref, resource_ref=None, service_name='Octavia'):
        """Deregister as a consumer for the specified cert.

        :param cert_ref: the UUID of the cert to retrieve
        :param resource_ref: Full HATEOAS reference to the consuming resource
        :param service_name: Friendly name for the consuming service

        :raises Exception: if deregistration fails
        """
        connection = barbican_common.BarbicanAuth.get_barbican_client()

        LOG.info(
            _LI("Deregistering as a consumer of {0} in Barbican.").format(
                cert_ref))
        try:
            connection.containers.remove_consumer(container_ref=cert_ref,
                                                  name=service_name,
                                                  url=resource_ref)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Error deregistering as a consumer of {0}: {1}").
                    format(cert_ref, str(e)))
Example #48
0
 def execute(self, deltas):
     """Handle network plugging based off deltas."""
     added_ports = {}
     for amp_id, delta in six.iteritems(deltas):
         added_ports[amp_id] = []
         for nic in delta.add_nics:
             interface = self.network_driver.plug_network(
                 delta.compute_id, nic.network_id)
             port = self.network_driver.get_port(interface.port_id)
             port.network = self.network_driver.get_network(port.network_id)
             for fixed_ip in port.fixed_ips:
                 fixed_ip.subnet = self.network_driver.get_subnet(
                     fixed_ip.subnet_id)
             added_ports[amp_id].append(port)
         for nic in delta.delete_nics:
             try:
                 self.network_driver.unplug_network(delta.compute_id,
                                                    nic.network_id)
             except base.NetworkNotFound:
                 LOG.debug("Network %d not found ", nic.network_id)
             except Exception:
                 LOG.exception(_LE("Unable to unplug network"))
     return added_ports
Example #49
0
    def store_cert(certificate,
                   private_key,
                   intermediates=None,
                   private_key_passphrase=None,
                   expiration=None,
                   name='Octavia TLS Cert'):
        """Stores a certificate in the certificate manager.

        :param certificate: PEM encoded TLS certificate
        :param private_key: private key for the supplied certificate
        :param intermediates: ordered and concatenated intermediate certs
        :param private_key_passphrase: optional passphrase for the supplied key
        :param expiration: the expiration time of the cert in ISO 8601 format
        :param name: a friendly name for the cert

        :returns: the container_ref of the stored cert
        :raises Exception: if certificate storage fails
        """
        connection = barbican_common.BarbicanAuth.get_barbican_client()

        LOG.info(
            _LI("Storing certificate container '{0}' in Barbican.").format(
                name))

        certificate_secret = None
        private_key_secret = None
        intermediates_secret = None
        pkp_secret = None

        try:
            certificate_secret = connection.secrets.create(
                payload=certificate, expiration=expiration, name="Certificate")
            private_key_secret = connection.secrets.create(
                payload=private_key, expiration=expiration, name="Private Key")
            certificate_container = connection.containers.create_certificate(
                name=name,
                certificate=certificate_secret,
                private_key=private_key_secret)
            if intermediates:
                intermediates_secret = connection.secrets.create(
                    payload=intermediates,
                    expiration=expiration,
                    name="Intermediates")
                certificate_container.intermediates = intermediates_secret
            if private_key_passphrase:
                pkp_secret = connection.secrets.create(
                    payload=private_key_passphrase,
                    expiration=expiration,
                    name="Private Key Passphrase")
                certificate_container.private_key_passphrase = pkp_secret

            certificate_container.store()
            return certificate_container.container_ref
        except Exception as e:
            for i in [
                    certificate_secret, private_key_secret,
                    intermediates_secret, pkp_secret
            ]:
                if i and i.secret_ref:
                    old_ref = i.secret_ref
                    try:
                        i.delete()
                        LOG.info(
                            _LI("Deleted secret {0} ({1}) during rollback.").
                            format(i.name, old_ref))
                    except Exception:
                        LOG.warning(
                            _LW("Failed to delete {0} ({1}) during rollback. This "
                                "might not be a problem.").format(
                                    i.name, old_ref))
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Error storing certificate data: {0}").format(str(e)))
Example #50
0
    def update_health(self, health):
        """This function is to update db info based on amphora status

        :param health: map object that contains amphora, listener, member info
        :type map: string
        :returns: null

        The input health data structure is shown as below:

        health = {
            "id": self.FAKE_UUID_1,
            "listeners": {
                "listener-id-1": {"status": constants.OPEN, "pools": {
                    "pool-id-1": {"status": constants.UP,
                                  "members": {"member-id-1": constants.ONLINE}
                                  }
                }
                }
            }
        }

        """
        session = db_api.get_session()

        # We need to see if all of the listeners are reporting in
        expected_listener_count = 0
        lbs_on_amp = self.amphora_repo.get_all_lbs_on_amphora(
            session, health['id'])
        for lb in lbs_on_amp:
            listener_count = self.listener_repo.count(session,
                                                      load_balancer_id=lb.id)
            expected_listener_count += listener_count

        listeners = health['listeners']

        # Do not update amphora health if the reporting listener count
        # does not match the expected listener count
        if len(listeners) == expected_listener_count:

            # if the input amphora is healthy, we update its db info
            self.amphora_health_repo.replace(
                session,
                health['id'],
                last_update=(datetime.datetime.utcnow()))
        else:
            LOG.warn(
                _LW('Amphora %(id)s health message reports %(found)i '
                    'listeners when %(expected)i expected'), {
                        'id': health['id'],
                        'found': len(listeners),
                        'expected': expected_listener_count
                    })

        # We got a heartbeat so lb is healthy until proven otherwise
        lb_status = constants.ONLINE

        # update listener and nodes db information
        for listener_id, listener in six.iteritems(listeners):

            listener_status = None
            # OPEN = HAProxy listener status nbconn < maxconn
            if listener.get('status') == constants.OPEN:
                listener_status = constants.ONLINE
            # FULL = HAProxy listener status not nbconn < maxconn
            elif listener.get('status') == constants.FULL:
                listener_status = constants.DEGRADED
                if lb_status == constants.ONLINE:
                    lb_status = constants.DEGRADED
            else:
                LOG.warn(
                    _LW('Listener %(list)s reported status of '
                        '%(status)s'), {
                            'list': listener_id,
                            'status': listener.get('status')
                        })

            try:
                if listener_status is not None:
                    self._update_status_and_emit_event(session,
                                                       self.listener_repo,
                                                       constants.LISTENER,
                                                       listener_id,
                                                       listener_status)
            except sqlalchemy.orm.exc.NoResultFound:
                LOG.error(_LE("Listener %s is not in DB"), listener_id)

            pools = listener['pools']
            for pool_id, pool in six.iteritems(pools):

                pool_status = None
                # UP = HAProxy backend has working or no servers
                if pool.get('status') == constants.UP:
                    pool_status = constants.ONLINE
                # DOWN = HAProxy backend has no working servers
                elif pool.get('status') == constants.DOWN:
                    pool_status = constants.ERROR
                    lb_status = constants.ERROR
                else:
                    LOG.warn(
                        _LW('Pool %(pool)s reported status of '
                            '%(status)s'), {
                                'pool': pool_id,
                                'status': pool.get('status')
                            })

                members = pool['members']
                for member_id, status in six.iteritems(members):

                    member_status = None
                    if status == constants.UP:
                        member_status = constants.ONLINE
                    elif status == constants.DOWN:
                        member_status = constants.ERROR
                        if pool_status == constants.ONLINE:
                            pool_status = constants.DEGRADED
                            if lb_status == constants.ONLINE:
                                lb_status = constants.DEGRADED
                    elif status == constants.NO_CHECK:
                        member_status = constants.NO_MONITOR
                    else:
                        LOG.warn(
                            _LW('Member %(mem)s reported status of '
                                '%(status)s'), {
                                    'mem': member_id,
                                    'status': status
                                })

                    try:
                        if member_status is not None:
                            self._update_status_and_emit_event(
                                session, self.member_repo, constants.MEMBER,
                                member_id, member_status)
                    except sqlalchemy.orm.exc.NoResultFound:
                        LOG.error(
                            _LE("Member %s is not able to update "
                                "in DB"), member_id)

                try:
                    if pool_status is not None:
                        self._update_status_and_emit_event(
                            session, self.pool_repo, constants.POOL, pool_id,
                            pool_status)
                except sqlalchemy.orm.exc.NoResultFound:
                    LOG.error(_LE("Pool %s is not in DB"), pool_id)

        # Update the load balancer status last
        # TODO(sbalukoff): This logic will need to be adjusted if we
        # start supporting multiple load balancers per amphora
        lb_id = self.amphora_repo.get(session,
                                      id=health['id']).load_balancer_id
        if lb_id is not None:
            try:
                self._update_status_and_emit_event(session,
                                                   self.loadbalancer_repo,
                                                   constants.LOADBALANCER,
                                                   lb_id, lb_status)
            except sqlalchemy.orm.exc.NoResultFound:
                LOG.error(_LE("Load balancer %s is not in DB"), lb_id)
Example #51
0
    def delete_listener(self, listener_id):
        self._check_listener_exists(listener_id)

        # check if that haproxy is still running and if stop it
        if os.path.exists(util.pid_path(listener_id)) and os.path.exists(
                os.path.join('/proc', util.get_haproxy_pid(listener_id))):
            cmd = "/usr/sbin/service haproxy-{0} stop".format(listener_id)
            try:
                subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
            except subprocess.CalledProcessError as e:
                LOG.error(_LE("Failed to stop HAProxy service: %s"), e)
                return flask.make_response(
                    flask.jsonify(
                        dict(message="Error stopping haproxy",
                             details=e.output)), 500)

        # parse config and delete stats socket
        try:
            cfg = self._parse_haproxy_file(listener_id)
            os.remove(cfg['stats_socket'])
        except Exception:
            pass

        # delete the ssl files
        try:
            shutil.rmtree(self._cert_dir(listener_id))
        except Exception:
            pass

        # disable the service
        init_system = util.get_os_init_system()
        init_path = util.init_path(listener_id, init_system)

        if init_system == consts.INIT_SYSTEMD:
            init_disable_cmd = "systemctl disable haproxy-{list}".format(
                list=listener_id)
        elif init_system == consts.INIT_SYSVINIT:
            init_disable_cmd = "insserv -r {file}".format(file=init_path)
        elif init_system != consts.INIT_UPSTART:
            raise util.UnknownInitError()

        if init_system != consts.INIT_UPSTART:
            try:
                subprocess.check_output(init_disable_cmd.split(),
                                        stderr=subprocess.STDOUT)
            except subprocess.CalledProcessError as e:
                LOG.error(
                    _LE("Failed to disable haproxy-%(list)s "
                        "service: %(err)s"), {
                            'list': listener_id,
                            'err': e
                        })
                return flask.make_response(
                    flask.jsonify(
                        dict(message="Error disabling haproxy-{0} service".
                             format(listener_id),
                             details=e.output)), 500)

        # delete the directory + init script for that listener
        shutil.rmtree(util.haproxy_dir(listener_id))
        if os.path.exists(init_path):
            os.remove(init_path)

        return flask.jsonify({'message': 'OK'})
Example #52
0
    def upload_haproxy_config(self, amphora_id, listener_id):
        """Upload the haproxy config

        :param amphora_id: The id of the amphora to update
        :param listener_id: The id of the listener
        """
        stream = Wrapped(flask.request.stream)
        # We have to hash here because HAProxy has a string length limitation
        # in the configuration file "peer <peername>" lines
        peer_name = octavia_utils.base64_sha1_string(amphora_id).rstrip('=')
        if not os.path.exists(util.haproxy_dir(listener_id)):
            os.makedirs(util.haproxy_dir(listener_id))

        name = os.path.join(util.haproxy_dir(listener_id), 'haproxy.cfg.new')
        flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
        # mode 00600
        mode = stat.S_IRUSR | stat.S_IWUSR
        with os.fdopen(os.open(name, flags, mode), 'wb') as file:
            b = stream.read(BUFFER)
            while (b):
                file.write(b)
                b = stream.read(BUFFER)

        # use haproxy to check the config
        cmd = "haproxy -c -L {peer} -f {config_file}".format(config_file=name,
                                                             peer=peer_name)

        try:
            subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            LOG.error(_LE("Failed to verify haproxy file: %s"), e)
            os.remove(name)  # delete file
            return flask.make_response(
                flask.jsonify(dict(message="Invalid request",
                                   details=e.output)), 400)

        # file ok - move it
        os.rename(name, util.config_path(listener_id))

        try:

            init_system = util.get_os_init_system()

            LOG.debug('Found init system: {0}'.format(init_system))

            init_path = util.init_path(listener_id, init_system)

            if init_system == consts.INIT_SYSTEMD:
                template = SYSTEMD_TEMPLATE
                init_enable_cmd = "systemctl enable haproxy-{list}".format(
                    list=listener_id)
            elif init_system == consts.INIT_UPSTART:
                template = UPSTART_TEMPLATE
            elif init_system == consts.INIT_SYSVINIT:
                template = SYSVINIT_TEMPLATE
                init_enable_cmd = "insserv {file}".format(file=init_path)
            else:
                raise util.UnknownInitError()

        except util.UnknownInitError:
            LOG.error(_LE("Unknown init system found."))
            return flask.make_response(
                flask.jsonify(
                    dict(
                        message="Unknown init system in amphora",
                        details="The amphora image is running an unknown init "
                        "system.  We can't create the init configuration "
                        "file for the load balancing process.")), 500)

        if init_system == consts.INIT_SYSTEMD:
            # mode 00644
            mode = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
        else:
            # mode 00755
            mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH
                    | stat.S_IXOTH)
        if not os.path.exists(init_path):
            with os.fdopen(os.open(init_path, flags, mode), 'w') as text_file:

                text = template.render(
                    peer_name=peer_name,
                    haproxy_pid=util.pid_path(listener_id),
                    haproxy_cmd=util.CONF.haproxy_amphora.haproxy_cmd,
                    haproxy_cfg=util.config_path(listener_id),
                    respawn_count=util.CONF.haproxy_amphora.respawn_count,
                    respawn_interval=(
                        util.CONF.haproxy_amphora.respawn_interval),
                    amphora_nsname=consts.AMPHORA_NAMESPACE,
                    HasIFUPAll=self._osutils.has_ifup_all())
                text_file.write(text)

        # Make sure the new service is enabled on boot
        if init_system != consts.INIT_UPSTART:
            try:
                subprocess.check_output(init_enable_cmd.split(),
                                        stderr=subprocess.STDOUT)
            except subprocess.CalledProcessError as e:
                LOG.error(
                    _LE("Failed to enable haproxy-%(list)s "
                        "service: %(err)s"), {
                            'list': listener_id,
                            'err': e
                        })
                return flask.make_response(
                    flask.jsonify(
                        dict(message="Error enabling haproxy-{0} service".
                             format(listener_id),
                             details=e.output)), 500)

        res = flask.make_response(flask.jsonify({'message': 'OK'}), 202)
        res.headers['ETag'] = stream.get_md5()
        return res
Example #53
0
class InvalidString(OctaviaException):
    message = _LE('Invalid characters in %(what)s')
Example #54
0
class InvalidL7PolicyAction(APIException):
    message = _LE('Invalid L7 Policy action specified: %(action)s')
    code = 400
Example #55
0
class ComputeBuildQueueTimeoutException(OctaviaException):
    message = _LE('Failed to get an amphora build slot.')
Example #56
0
class InvalidL7PolicyArgs(APIException):
    message = _LE('Invalid L7 Policy arguments: %(msg)s')
    code = 400
Example #57
0
class InvalidRegex(OctaviaException):
    message = _LE('Unable to parse regular expression: %(e)s')
Example #58
0
class ServerGroupObjectDeleteException(OctaviaException):
    message = _LE('Failed to delete server group object.')
Example #59
0
class InvalidURL(OctaviaException):
    message = _LE('Not a valid URL: %(url)s')
Example #60
0
class InvalidL7Rule(OctaviaException):
    message = _LE('Invalid L7 Rule: $(msg)s')