Example #1
0
    def _makeImageService(self, resource_root):
        from provisioningserver.rackdservices.image import (
            BootImageEndpointService)
        from twisted.internet.endpoints import AdoptedStreamServerEndpoint
        port = 5248  # config["port"]
        # Make a socket with SO_REUSEPORT set so that we can run multiple we
        # applications. This is easier to do from outside of Twisted as there's
        # not yet official support for setting socket options.
        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except socket_error as e:
            # Python's socket module was compiled using modern headers
            # thus defining SO_REUSEPORT would cause issues as it might
            # running in older kernel that does not support SO_REUSEPORT.

            # XXX andreserl 2015-04-08 bug=1441684: We need to add a warning
            # log message when we see this error, and a test for it.
            if e.errno != ENOPROTOOPT:
                raise e
        s.bind(('::', port))
        # Use a backlog of 50, which seems to be fairly common.
        s.listen(50)
        # Adopt this socket into Twisted's reactor.
        site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(),
                                                    s.family)
        site_endpoint.port = port  # Make it easy to get the port number.
        site_endpoint.socket = s  # Prevent garbage collection.

        image_service = BootImageEndpointService(resource_root=resource_root,
                                                 endpoint=site_endpoint)
        image_service.setName("image_service")
        return image_service
Example #2
0
    def _makeHTTPService(self):
        """Create the HTTP service."""
        from provisioningserver.rackdservices.http import HTTPResource
        from twisted.application.internet import StreamServerEndpointService
        from twisted.internet.endpoints import AdoptedStreamServerEndpoint
        from provisioningserver.utils.twisted import SiteNoLog

        port = 5249
        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except socket_error as e:
            if e.errno != ENOPROTOOPT:
                raise e
        s.bind(('::', port))
        # Use a backlog of 50, which seems to be fairly common.
        s.listen(50)
        # Adopt this socket into Twisted's reactor.
        site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(),
                                                    s.family)
        site_endpoint.port = port  # Make it easy to get the port number.
        site_endpoint.socket = s  # Prevent garbage collection.

        http_service = StreamServerEndpointService(site_endpoint,
                                                   SiteNoLog(HTTPResource()))
        http_service.setName("http_service")
        return http_service
Example #3
0
    def _makeHTTPService(self, port, path, prefix=None):
        from twisted.internet.endpoints import AdoptedStreamServerEndpoint
        from provisioningserver.http import (
            create_reuse_socket,
            EndpointService,
        )

        # Create the HTTP socket binded to the provided port.
        s = create_reuse_socket()
        s.bind(('::', port))

        # Use a backlog of 50, which seems to be fairly common.
        s.listen(50)

        # Adopt this socket into Twisted's reactor.
        site_endpoint = AdoptedStreamServerEndpoint(
            reactor, s.fileno(), s.family)
        site_endpoint.port = port  # Make it easy to get the port number.
        site_endpoint.socket = s  # Prevent garbage collection.

        # Setup the endpoing with the resource path.
        service = EndpointService(
            resource_root=path, endpoint=site_endpoint, prefix=prefix)
        service.setName("http_endpoint")
        return service
Example #4
0
    def _makeEndpoint(self):
        """Make the endpoint for the webapp."""
        # Make a socket with SO_REUSEPORT set so that we can run multiple web
        # applications. This is easier to do from outside of Twisted as there's
        # not yet official support for setting socket options.
        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        # N.B, using the IPv6 INADDR_ANY means that getpeername() returns
        # something like: ('::ffff:192.168.133.32', 40588, 0, 0)
        s.bind(("::", self.port))
        # Use a backlog of 50, which seems to be fairly common.
        s.listen(50)

        # Adopt this socket into Twisted's reactor setting the endpoint.
        endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family)
        endpoint.port = self.port  # Make it easy to get the port number.
        endpoint.socket = s  # Prevent garbage collection.
        return endpoint
Example #5
0
def make_WebApplicationService(postgresListener, statusWorker):
    from maasserver.webapp import WebApplicationService
    site_port = DEFAULT_PORT  # config["port"]
    # Make a socket with SO_REUSEPORT set so that we can run multiple web
    # applications. This is easier to do from outside of Twisted as there's
    # not yet official support for setting socket options.
    s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
    # N.B, using the IPv6 INADDR_ANY means that getpeername() returns something
    # like: ('::ffff:192.168.133.32', 40588, 0, 0)
    s.bind(('::', site_port))
    # Use a backlog of 50, which seems to be fairly common.
    s.listen(50)
    # Adopt this socket into Twisted's reactor.
    site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family)
    site_endpoint.port = site_port  # Make it easy to get the port number.
    site_endpoint.socket = s  # Prevent garbage collection.
    site_service = WebApplicationService(site_endpoint, postgresListener,
                                         statusWorker)
    return site_service
Example #6
0
def makeAgentService(store):
    """
    Returns a service which will process GatewayAMPCommands, using a socket
    file descripter acquired by launchd

    @param store: an already opened store
    @returns: service
    """
    from twisted.internet import reactor

    sockets = launchActivateSocket("AgentSocket")
    fd = sockets[0]

    family = socket.AF_INET
    endpoint = AdoptedStreamServerEndpoint(reactor, fd, family)

    directory = store.directoryService()

    def becameInactive():
        log.warn("Agent inactive; shutting down")
        reactor.stop()

    from twistedcaldav.config import config
    inactivityDetector = InactivityDetector(
        reactor, config.AgentInactivityTimeoutSeconds, becameInactive
    )
    root = Resource()
    root.putChild(
        "gateway",
        AgentGatewayResource(
            store, directory, inactivityDetector
        )
    )

    # We need this service to be able to return com.apple.calendarserver,
    # so tell it not to suppress system accounts.
    directory = OpenDirectoryDirectoryService(
        "/Local/Default", suppressSystemRecords=False
    )

    portal = Portal(
        AgentRealm(root, [u"com.apple.calendarserver"]),
        [HTTPDigestCredentialChecker(directory)]
    )
    credentialFactory = NoQOPDigestCredentialFactory(
        "md5", "/Local/Default"
    )
    wrapper = HTTPAuthSessionWrapper(portal, [credentialFactory])

    site = Site(wrapper)

    return StreamServerEndpointService(endpoint, site)
Example #7
0
def _foolscapEndpointForPortNumber(portnum):
    """
    Create an endpoint that can be passed to ``Tub.listen``.

    :param portnum: Either an integer port number indicating which TCP/IPv4
        port number the endpoint should bind or ``None`` to automatically
        allocate such a port number.

    :return: A two-tuple of the integer port number allocated and a
        Foolscap-compatible endpoint object.
    """
    if portnum is None:
        # Bury this reactor import here to minimize the chances of it having
        # the effect of installing the default reactor.
        from twisted.internet import reactor
        if fcntl is not None and IReactorSocket.providedBy(reactor):
            # On POSIX we can take this very safe approach of binding the
            # actual socket to an address.  Once the bind succeeds here, we're
            # no longer subject to any future EADDRINUSE problems.
            s = socket.socket()
            try:
                s.bind(('', 0))
                portnum = s.getsockname()[1]
                s.listen(1)
                # File descriptors are a relatively scarce resource.  The
                # cleanup process for the file descriptor we're about to dup
                # is unfortunately complicated.  In particular, it involves
                # the Python garbage collector.  See CleanupEndpoint for
                # details of that.  Here, we need to make sure the garbage
                # collector actually runs frequently enough to make a
                # difference.  Normally, the garbage collector is triggered by
                # allocations.  It doesn't know about *file descriptor*
                # allocation though.  So ... we'll "teach" it about those,
                # here.
                fileDescriptorResource.allocate()
                fd = os.dup(s.fileno())
                flags = fcntl.fcntl(fd, fcntl.F_GETFD)
                flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC
                fcntl.fcntl(fd, fcntl.F_SETFD, flags)
                endpoint = AdoptedStreamServerEndpoint(reactor, fd,
                                                       socket.AF_INET)
                return (portnum, CleanupEndpoint(endpoint, fd))
            finally:
                s.close()
        else:
            # Get a random port number and fall through.  This is necessary on
            # Windows where Twisted doesn't offer IReactorSocket.  This
            # approach is error prone for the reasons described on
            # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787
            portnum = allocate_tcp_port()
    return (portnum, native_str("tcp:%d" % (portnum, )))
Example #8
0
 def parseStreamServer(self, reactor, fd):
     log.msg("Adopting {}".format(fd))
     # AdoptedStreamServerEndpoint wants to own the file descriptor.  It
     # will duplicate it and then close the one we pass in.  This means it
     # is really only possible to adopt a particular file descriptor once.
     #
     # This wouldn't matter except one of the tests wants to stop one of
     # the nodes and start it up again.  This results in exactly an attempt
     # to adopt a particular file descriptor twice.
     #
     # So we'll dup it ourselves.  AdoptedStreamServerEndpoint can do
     # whatever it wants to the result - the original will still be valid
     # and reusable.
     return AdoptedStreamServerEndpoint(reactor, os.dup(int(fd)), AF_INET)
Example #9
0
def foolscapEndpointForPortNumber(portnum):
    """
    Create an endpoint that can be passed to ``Tub.listen``.

    :param portnum: Either an integer port number indicating which TCP/IPv4
        port number the endpoint should bind or ``None`` to automatically
        allocate such a port number.

    :return: A two-tuple of the integer port number allocated and a
        Foolscap-compatible endpoint object.
    """
    if portnum is None:
        # Bury this reactor import here to minimize the chances of it having
        # the effect of installing the default reactor.
        from twisted.internet import reactor
        if fcntl is not None and IReactorSocket.providedBy(reactor):
            # On POSIX we can take this very safe approach of binding the
            # actual socket to an address.  Once the bind succeeds here, we're
            # no longer subject to any future EADDRINUSE problems.
            s = socket()
            try:
                s.bind(('', 0))
                portnum = s.getsockname()[1]
                s.listen(1)
                fd = os.dup(s.fileno())
                flags = fcntl.fcntl(fd, fcntl.F_GETFD)
                flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC
                fcntl.fcntl(fd, fcntl.F_SETFD, flags)
                return (
                    portnum,
                    AdoptedStreamServerEndpoint(reactor, fd, AF_INET),
                )
            finally:
                s.close()
        else:
            # Get a random port number and fall through.  This is necessary on
            # Windows where Twisted doesn't offer IReactorSocket.  This
            # approach is error prone for the reasons described on
            # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787
            portnum = iputil.allocate_tcp_port()
    return (portnum, "tcp:%d" % (portnum, ))
    def test_proxying(self):
        pems = node_pems()

        # Create client and server tubs we can use to speak Foolscap through
        # the proxy.  This should demonstrate the proxy is working.
        client = Tub(pems.example())
        client.startService()
        self.addCleanup(client.stopService)

        server = Tub(pems.example())
        server.startService()
        self.addCleanup(server.stopService)

        # Get an arbitrary local address on which the server tub can listen.
        while True:
            server_socket = socket()
            try:
                server_socket.bind(("", 0))
            except Exception as e:
                print(e)
                server_socket.close()
            else:
                server_socket.listen(1)
                self.addCleanup(server_socket.close)
                break

        server_address = server_socket.getsockname()
        msg("Got server address {}".format(server_address))
        server_endpoint = AdoptedStreamServerEndpoint(
            self.reactor,
            server_socket.fileno(),
            AF_INET,
        )
        server.listenOn(server_endpoint)

        # Get a grid router that knows where the server tub really is and so
        # should be able to proxy connections to it for us.
        grid_router = _GridRouterService(self.reactor)
        grid_router.set_route_mapping(
            freeze({
                server.getTubID().decode("ascii"): (None, server_address),
            }))

        # Start the proxy listening.
        factory = grid_router.factory()
        d = TCP4ServerEndpoint(self.reactor, 0).listen(factory)

        def listening(proxy_port):
            self.addCleanup(proxy_port.stopListening)

            # Tell the server tub where the _proxy_ is it generates a furl
            # pointing at the proxy.  We'll use that furl to connect with the
            # client tub and rely on the proxy to get us to the right place.
            host = proxy_port.getHost().host.decode("ascii")
            port_number = proxy_port.getHost().port
            location = u"{host}:{port}".format(
                host=host,
                port=port_number,
            )
            server.setLocation(location.encode("ascii"))
            msg("Set server Tub location {}".format(location))
            # Register something arbitrary that we can poke at.
            furl = server.registerReference(Referenceable())

            # Try to connect to the server tub with the client tub through the
            # proxy.
            d = Deferred()
            reconn = client.connectTo(furl, d.callback)
            self.addCleanup(reconn.stopConnecting)
            return d

        d.addCallback(listening)

        def connected(ref):
            pass

        d.addCallback(connected)
        return d