예제 #1
0
def check_output_input(*args, **kwargs):

    if sys.version_info[0] >= 3:
        return subprocess.check_output(*args, **kwargs)
    else:
        if 'stdout' in kwargs:
            raise ValueError(_('stdout argument not allowed, '
                               'it will be overridden.'))
        if 'input' in kwargs:
            if 'stdin' in kwargs:
                raise ValueError(_('stdin and input arguments '
                                   'may not both be used.'))
            inputdata = kwargs['input']
            del kwargs['input']
            kwargs['stdin'] = subprocess.PIPE
        else:
            inputdata = None

        process = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs)

        try:
            output, unused_err = process.communicate(inputdata)
        except Exception as e:
            process.kill()
            process.wait()
            raise e

        retcode = process.poll()

        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = args[0]
            raise subprocess.CalledProcessError(retcode, cmd, output=output)
        return output
예제 #2
0
    def verify(self, signer_requirements, path, sgn_value):
        """Verify the authenticity of the incoming data

        :param signer_requirements: what we expect of the key; right now,
        the CN of the signer
        :param path: path where the JSON object was found
        :param sgn_value: The datastructure found at that path
        :return: confirmed original value from JWT token.
        :raise A JWTSigningFailed is raised if the verification fails.
        """

        if sgn_value is None:
            raise JWTSigningFailed(
                _("Invalid empty value at path %s") % (path))

        try:
            # Load the certificate and verify that it is both a suitable
            # certificate for this key and one we trust the origin of
            vcert_str = sgn_value.get("certificate", "")
            # ("" is an invalid key)

            # py3.x note:
            # In some unit tests, vcert_str is returned as type bytes while in
            # some others it is type str. A bytes-type object is what the
            # crypto apis expect and hence the following check.
            # TODO(JB): replace with more elegant solution if possible
            if type(vcert_str) is str:
                vcert_str = bytes(vcert_str, 'ascii')

            # TODO(ijw): how does this fail?
            vcert_obj = load_pem_x509_certificate(vcert_str, default_backend())

            vpublic_key = vcert_obj.public_key()

            self._check_node_name(signer_requirements, vcert_obj)
            # TODO(ijw): what checks the cert is signed with the CA?
            self._verify_certificate(vcert_str)

            # Unpack the JWT to its raw data
            jwtok = sgn_value.get("jwt", "")
            # ("" is an invalid token)
            dval = jwt.decode(jwtok, vpublic_key, algorithms='RS256')

            # Check the ancillary tags of the raw data
            self._check_path(dval, path)
            # TODO(ijw): check delta

            # Get and return the originally provided value
            return dval["value"]

        except jwt.InvalidTokenError:
            raise JWTSigningFailed(_("InvalidTokenError: path :%s") % path)
예제 #3
0
class GpeVNIInUse(n_exc.NeutronException):
    """GPE network creation failed exception due to the VNI being in use.

    :param vni_id: The ID of the GPE VNI that's in use.
    """
    message = _("Invalid GPE VNI value %(vni_id)s for allocation "
                "The VNI is already in use by another GPE network")
예제 #4
0
    def _check_node_name(self, nodeName, vcert_obj):
        """Check the common name of the signer certificate.

        Verify the role of the signer certificate matches the expected
        role of the signer.
        :param nodeName: A named tuple containing either the expected signer
        hostname or a regexp to check the signer hostname.
        :param vcert_obj: The X509 certificate of the signer
        raise: JWTSigningError if not valid.
        """

        subject_name = vcert_obj.subject
        commonNames = subject_name.get_attributes_for_oid(
            oid.NameOID.COMMON_NAME)

        commonName = commonNames[0]
        if nodeName.isRegexp:
            if re.match(nodeName.value, commonName.value):
                return
        elif nodeName.value == commonName.value:
            return

        raise JWTSigningFailed(
            _("cert says node name is %(cn)s and we want %(nn)s") % {
                'cn': commonName.value,
                'nn': str(nodeName.value)
            })
예제 #5
0
class GpeVNIInvalid(n_exc.NeutronException):
    """GPE network creation failed exception due to the VNI being invalid.

    :param vni_id: The ID of the GPE VNI that's invalid.
    """
    message = _("Invalid GPE VNI value %(vni_id)s for allocation "
                "or deallocation ")
예제 #6
0
    def _verify_certificate(self, vcert):
        """Confirm this certificate is in a chain of trust

        We have a CA, and we want to know we're seeing a certificate
        that this CA has signed.
        """
        certificate = crypto.load_certificate(crypto.FILETYPE_PEM, vcert)

        store_ctx = crypto.X509StoreContext(self.store, certificate)
        result = store_ctx.verify_certificate()
        if result is not None:
            raise JWTSigningFailed(_("Certificate is not trusted"))
예제 #7
0
    def _check_path(self, dval, path):
        """Check the signed path matches where the data was found

        :param dval: the signed data
        :param path: the path at which the signed data was stored
        :raise JWTSigningError: if not valid.
        """
        if (dval["path"] != path):
            raise JWTSigningFailed(
                _("path is %(dpth)s in data and we want %(pth)s") % {
                    'dpth': dval["path"],
                    'pth': path
                })
예제 #8
0
class GpeVNIRangeError(n_exc.NeutronException):
    """An exception indicating an invalid GPE VNI range was specified.

    :param vni_range: The invalid vni range specified in the
                      'start:end' format
    """
    message = _("Invalid VNI range string for the GPE network. Expect a "
                "string in the form %(vni_range)s")

    def __init__(self, **kwargs):
        # Convert the vni_range tuple to 'start:end' format for display
        if isinstance(kwargs['vni_range'], tuple):
            kwargs['vni_range'] = "%d:%d" % kwargs['vni_range']
        super(GpeVNIRangeError, self).__init__(**kwargs)
예제 #9
0
def check_output_input(*args, **kwargs):

    if sys.version_info[0] >= 3:
        return subprocess.check_output(*args, **kwargs)
    else:
        if 'stdout' in kwargs:
            raise ValueError(
                _('stdout argument not allowed, '
                  'it will be overridden.'))
        if 'input' in kwargs:
            if 'stdin' in kwargs:
                raise ValueError(
                    _('stdin and input arguments '
                      'may not both be used.'))
            inputdata = kwargs['input']
            del kwargs['input']
            kwargs['stdin'] = subprocess.PIPE
        else:
            inputdata = None

        process = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs)

        try:
            output, unused_err = process.communicate(inputdata)
        except Exception as e:
            process.kill()
            process.wait()
            raise e

        retcode = process.poll()

        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = args[0]
            raise subprocess.CalledProcessError(retcode, cmd, output=output)
        return output
예제 #10
0
    def run(self):
        """Run indefinitely, calling callbacks when interfaces change

        This uses just the socket API and so should be friendly with
        eventlet.  Ensure your callbacks are eventlet-safe if you do
        this.
        """
        def messages(s):
            """Iterator providing all messages in a netlink stream"""
            while True:
                incoming = s.recv(65535)

                # Work through the messages in this packet
                while len(incoming) > 0:
                    try:
                        msg_type, flags, seq, pid, data, incoming = \
                            unpack_nlmsg(incoming)
                        yield msg_type, flags, seq, pid, data
                    except IncompleteMsg:
                        # We seem to have half a message.
                        # This shouldn't happen, so we go with
                        # discarding it and moving on to the next
                        # packet
                        LOG.warning('Received incomplete message from'
                                    ' NETLINK, dropping')

        addr_offset = 0
        while True:
            s = None
            try:
                # Create the netlink socket and bind to RTMGRP.LINK messages
                s = socket.socket(socket.AF_NETLINK,
                                  socket.SOCK_RAW,
                                  socket.NETLINK_ROUTE)

                # Our task is to find a unique number for the socket.  Other
                # processes can use whatever number they like, so the offset
                # is used to manage possible conflicts.
                while True:
                    try:
                        s.bind((addr_offset << 16 | os.getpid(), RTMGRP.LINK))
                        break
                    except OSError as e:
                        if e.errno == errno.EADDRINUSE:
                            LOG.warning(
                                'Trying another address for netlink socket')
                            addr_offset += 1

                # Re-issue a 'tell me all your interfaces' request, allowing
                # us to resync with either initial state or missed change
                # messages.

                get_links = pack_linkrequest(NLMSG.RTM_GETLINK,
                                             NLM_F.REQUEST | NLM_F.DUMP)
                s.send(get_links)
                resync_links = set()

                for msg_type, flags, seq, pid, data in messages(s):

                    if msg_type == NLMSG.NOOP:
                        # Meh.
                        continue
                    elif msg_type == NLMSG.ERROR:
                        # Force a netlink reset.
                        raise Exception(_("Error received on netlink socket"))
                    elif msg_type == NLMSG.DONE:
                        # We were presumably resyncing, and now we have
                        # everything.

                        # Having processed all of the incoming message,
                        # consider whether we have either new or dead links:
                        LOG.debug('getlink: saw links %s',
                                  ', '.join(resync_links))
                        new_links = resync_links - self.devices
                        dead_links = self.devices - resync_links

                        for f in new_links:
                            self._dev_add(f)
                        for f in dead_links:
                            self._dev_del(f)

                        resync_links = None
                        continue

                    # We're interested in tap devices appearing and
                    # disappearing. Anything else can pass us by.
                    if msg_type not in (NLMSG.RTM_GETLINK,
                                        NLMSG.RTM_NEWLINK,
                                        NLMSG.RTM_DELLINK):
                        continue

                    if_type, flags, data = unpack_linkmsg(data)

                    link_name = None
                    while len(data) > 0:
                        # This check comes from RTA_OK, and terminates a string
                        # of routing attributes.

                        attr_type, attr_body, data = unpack_attr(data)

                        # Hoorah, a link is up!
                        if attr_type == IFLA.IFNAME:
                            # As returned, includes a C-style \0
                            link_name = attr_body[:-1]
                            # py3 note:
                            # link_name is a bytes object so explicitly convert
                            # to string in case of py3 otherwise we get an
                            # exception.
                            link_name = link_name.decode('ascii')

                    if link_name is None:
                        raise Exception(_("Add-link message without if name"))

                    if msg_type == NLMSG.RTM_NEWLINK:
                        if resync_links is not None:
                            # We're actually in a dump
                            resync_links.add(link_name)
                        else:
                            self._dev_add(link_name)
                    else:
                        self._dev_del(link_name)

            except KeyboardInterrupt:
                raise
            except Exception:
                LOG.exception("Unexpected exception in device watching"
                              " thread - resetting")
            finally:
                if s is not None:
                    s.close()
                    s = None
예제 #11
0
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from networking_vpp._i18n import _
from oslo_config import cfg

vpp_opts = [
    cfg.StrOpt('physnets',
               help=_("Comma-separated list of net-name:interface-name for "
                      "physical connections")),
    cfg.StrOpt('vxlan_src_addr',
               help=_("Source address used for VXLAN tunnel packets.")),
    cfg.StrOpt('vxlan_bcast_addr',
               help=_("Broadcast address used to set up VXLAN tunnels.")),
    cfg.StrOpt('vxlan_vrf',
               help=_("VPP's VRF for the encapped VXLAN packets.")),
    cfg.StrOpt('etcd_host',
               default="127.0.0.1",
               help=_("Etcd host IP address(es) to connect etcd client."
                      "It takes two formats: single IP/host or a multiple "
                      "hosts list with this format: 'IP:Port,IP:Port'. "
                      "e.g: 192.168.1.1:2379,192.168.1.2:2379.  If port "
                      "is absent, etcd_port is used.")),
    cfg.IntOpt('etcd_port',
               default=4001,
예제 #12
0
class InvalidEtcHostsConfig(n_exec.NeutronException):
    message = _("Invalid etc host config. Expect comma-separated list of "
                "<Host> or <Host:Port> format")
예제 #13
0
class InvalidEtcHostConfig(n_exec.NeutronException):
    message = _("Invalid etc host config. Expect an IP or host name in "
                "the form <Host> or <Host:Port>")
예제 #14
0
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from networking_vpp._i18n import _
from networking_vpp import etcdutils
from oslo_config import cfg

_vpp_opts = [
    cfg.StrOpt('physnets',
               help=_("Comma-separated list of net-name:interface-name for "
                      "physical connections")),
    cfg.StrOpt('gpe_src_cidr', default=None,
               help=_("The source_IP/Mask used for GPE tunnel packets. ")),
    cfg.StrOpt('gpe_locators', default=None,
               help=_("The physnet name(s) used as the underlay "
                      "(i.e. locator) interface by GPE. The agent will "
                      "program the GPE source CIDR on this interface "
                      "and will assume that it has Layer3 reachability "
                      "with all other GPE locator interfaces "
                      "specified on compute and network nodes. In the "
                      "current implementation only a single locator "
                      "is supported.")),
    cfg.IntOpt('etcd_write_time', default=20,
               help=_("The period of time alloted to etcd write before it is "
                      "timed out.")),
    cfg.IntOpt('forward_worker_master_lease_time', default=30,
예제 #15
0
class InvalidEtcdCAConfig(n_exec.NeutronException):
    message = _("Invalid etcd CA config.")
예제 #16
0
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from networking_vpp._i18n import _
from networking_vpp import etcdutils
from oslo_config import cfg

_vpp_opts = [
    cfg.StrOpt('physnets',
               help=_("Comma-separated list of net-name:interface-name for "
                      "physical connections")),
    cfg.StrOpt('gpe_src_cidr', default=None,
               help=_("The source_IP/Mask used for GPE tunnel packets. ")),
    cfg.StrOpt('gpe_locators', default=None,
               help=_("The physnet name(s) used as the underlay "
                      "(i.e. locator) interface by GPE. The agent will "
                      "program the GPE source CIDR on this interface "
                      "and will assume that it has Layer3 reachability "
                      "with all other GPE locator interfaces "
                      "specified on compute and network nodes. In the "
                      "current implementation only a single locator "
                      "is supported.")),
    cfg.IntOpt('etcd_write_time', default=20,
               help=_("The period of time alloted to etcd write before it is "
                      "timed out.")),
    cfg.IntOpt('forward_worker_master_lease_time', default=30,
예제 #17
0
            # Thrown if the directory is not empty, which we error log
            LOG.error("Directory path:%s is not empty and cannot be deleted",
                      path)
        except etcd.EtcdKeyNotFound:
            # Already gone, so not a problem
            pass


# Base connection to etcd, using standard options.

_etcd_conn_opts = [
    cfg.StrOpt('etcd_host',
               default="127.0.0.1",
               help=_("Etcd host IP address(es) to connect etcd client."
                      "It takes two formats: single IP/host or a multiple "
                      "hosts list with this format: 'IP:Port,IP:Port'. "
                      "e.g: 192.168.1.1:2379,192.168.1.2:2379.  If port "
                      "is absent, etcd_port is used.")),
    cfg.IntOpt('etcd_port',
               default=4001,
               help=_("Etcd port to connect the etcd client.  This can "
                      "be overridden on a per-host basis if the multiple "
                      "host form of etcd_host is used.")),
    cfg.StrOpt('etcd_user',
               default=None,
               help=_("Username for etcd authentication")),
    cfg.StrOpt('etcd_pass',
               default=None,
               secret=True,
               help=_("Password for etcd authentication")),
    # TODO(ijw): make false default
예제 #18
0
    def run(self):
        """Run indefinitely, calling callbacks when interfaces change

        This uses just the socket API and so should be friendly with
        eventlet.  Ensure your callbacks are eventlet-safe if you do
        this.
        """
        def messages(s):
            """Iterator providing all messages in a netlink stream"""
            while True:
                incoming = s.recv(65535)

                # Work through the messages in this packet
                while len(incoming) > 0:
                    try:
                        msg_type, flags, seq, pid, data, incoming = \
                            unpack_nlmsg(incoming)
                        yield msg_type, flags, seq, pid, data
                    except IncompleteMsg:
                        # We seem to have half a message.
                        # This shouldn't happen, so we go with
                        # discarding it and moving on to the next
                        # packet
                        LOG.warning('Received incomplete message from'
                                    ' NETLINK, dropping')

        while True:
            s = None
            try:
                # Create the netlink socket and bind to RTMGRP.LINK messages
                s = socket.socket(socket.AF_NETLINK,
                                  socket.SOCK_RAW,
                                  socket.NETLINK_ROUTE)
                s.bind((os.getpid(), RTMGRP.LINK))

                # Re-issue a 'tell me all your interfaces' request, allowing
                # us to resync with either initial state or missed change
                # messages.

                get_links = pack_linkrequest(NLMSG.RTM_GETLINK,
                                             NLM_F.REQUEST | NLM_F.DUMP)
                s.send(get_links)
                resync_links = set()

                for msg_type, flags, seq, pid, data in messages(s):

                    if msg_type == NLMSG.NOOP:
                        # Meh.
                        continue
                    elif msg_type == NLMSG.ERROR:
                        # Force a netlink reset.
                        raise Exception(_("Error received on netlink socket"))
                    elif msg_type == NLMSG.DONE:
                        # We were presumably resyncing, and now we have
                        # everything.

                        # Having processed all of the incoming message,
                        # consider whether we have either new or dead links:
                        LOG.debug('getlink: saw links %s',
                                  ', '.join(resync_links))
                        new_links = resync_links - self.devices
                        dead_links = self.devices - resync_links

                        for f in new_links:
                            self._dev_add(f)
                        for f in dead_links:
                            self._dev_del(f)

                        resync_links = None
                        continue

                    # We're interested in tap devices appearing and
                    # disappearing. Anything else can pass us by.
                    if msg_type not in (NLMSG.RTM_GETLINK,
                                        NLMSG.RTM_NEWLINK,
                                        NLMSG.RTM_DELLINK):
                        continue

                    if_type, flags, data = unpack_linkmsg(data)

                    link_name = None
                    while len(data) > 0:
                        # This check comes from RTA_OK, and terminates a string
                        # of routing attributes.

                        attr_type, attr_body, data = unpack_attr(data)

                        # Hoorah, a link is up!
                        if attr_type == IFLA.IFNAME:
                            # As returned, includes a C-style \0
                            link_name = attr_body[:-1]
                            # py3 note:
                            # link_name is a bytes object so explicitly convert
                            # to string in case of py3 otherwise we get an
                            # exception.
                            if six.PY3:
                                link_name = link_name.decode('ascii')
                            break

                    if link_name is None:
                        raise Exception(_("Add-link message without if name"))

                    if msg_type == NLMSG.RTM_NEWLINK:
                        if resync_links is not None:
                            # We're actually in a dump
                            resync_links.add(link_name)
                        else:
                            self._dev_add(link_name)
                    else:
                        self._dev_del(link_name)

            except KeyboardInterrupt:
                raise
            except Exception:
                LOG.exception("Unexpected exception in device watching"
                              " thread - resetting")
            finally:
                if s is not None:
                    s.close()
                    s = None
예제 #19
0
            self.etcd_client.delete(path, dir=True)
        except etcd.EtcdNotFile:
            # Thrown if the directory is not empty, which we error log
            LOG.error("Directory path:%s is not empty and cannot be deleted",
                      path)
        except etcd.EtcdKeyNotFound:
            # Already gone, so not a problem
            pass

# Base connection to etcd, using standard options.

_etcd_conn_opts = [
    cfg.StrOpt('etcd_host', default="127.0.0.1",
               help=_("Etcd host IP address(es) to connect etcd client."
                      "It takes two formats: single IP/host or a multiple "
                      "hosts list with this format: 'IP:Port,IP:Port'. "
                      "e.g: 192.168.1.1:2379,192.168.1.2:2379.  If port "
                      "is absent, etcd_port is used.")),
    cfg.IntOpt('etcd_port', default=4001,
               help=_("Etcd port to connect the etcd client.  This can "
                      "be overridden on a per-host basis if the multiple "
                      "host form of etcd_host is used.")),
    cfg.StrOpt('etcd_user', default=None,
               help=_("Username for etcd authentication")),
    cfg.StrOpt('etcd_pass', default=None,
               help=_("Password for etcd authentication")),
    # TODO(ijw): make false default
    cfg.BoolOpt('etcd_insecure_explicit_disable_https', default=True,
                help=_("Use TLS to access etcd")),
    cfg.StrOpt('etcd_ca_cert', default=None,
               help=_("etcd CA certificate file path")),
예제 #20
0
class GpeVNIUnavailable(n_exc.NeutronException):
    """GPE network creation failed exception due to a VNI being unavailable.

    """
    message = _("A GPE VNI is unavailable for allocation")