Пример #1
0
def request_vhost(locker, hostname, path, user=None, desc=''):
    """Request hostname as a vhost for the given locker and path.

    Throws a UserError if the request is invalid, otherwise returns
    a human-readable status message and sends a zephyr."""
    locker = locker.encode('utf-8')
    hostname, reqtype = validate_hostname(hostname, locker)
    path = path.encode('utf-8')
    path = validate_path(path)
    message = "The hostname '%s' is now configured." % hostname

    if user is None:
        user = current_user()

    if reqtype == 'moira':
        # actually_create_vhost does this check for other reqtypes
        check_if_already_exists(hostname, locker)
        t = queue.Ticket.create(locker,
                                hostname,
                                path,
                                requestor=user,
                                purpose=desc)
        short = hostname[:-len('.mit.edu')]
        mail.create_ticket(subject="scripts-vhosts CNAME request: %s" % short,
                           body="""Heyas,

%(user)s requested %(hostname)s for locker '%(locker)s' path %(path)s.
Go to %(url)s to approve it.

Purpose:
%(desc)s

Love,
~Scripts Pony
""" % dict(short=short,
           user=user,
           locker=locker,
           hostname=hostname,
           desc=desc,
           path=path,
           url=tg.request.host_url + tg.url('/ticket/%s' % t.id)),
                           id=t.id,
                           requestor=user)
        message = "We will request the hostname %s; mit.edu hostnames generally take 2-3 business days to become active." % hostname
    else:
        # Actually create the vhost
        actually_create_vhost(locker, hostname, path)
    if is_sudoing():
        sudobit = '+scripts-pony-acl'
        forbit = ' (for %s)' % user
    else:
        sudobit = ''
        forbit = ''
    logmessage = "%s%s requested %s for locker '%s' path '%s'%s (Purpose: %s)" % (
        current_user(), sudobit, hostname, locker, path, forbit, desc)

    log.info(logmessage)
    return message
Пример #2
0
def validate_hostname(hostname, locker):
    hostname = hostname.lower().encode("utf-8")
    if not HOSTNAME_PATTERN.search(hostname) or hostname.endswith(".invalid"):
        if "." not in hostname:
            raise UserError(
                "'%s' is not an absolute hostname.  Do you mean '%s.mit.edu'?"
                % (hostname, hostname)
            )
        else:
            raise UserError("'%s' is not a valid hostname." % hostname)

    if hostname.endswith(".scripts.mit.edu"):
        reqtype = "subscripts"
        if not hostname.endswith("." + locker + ".scripts.mit.edu"):
            raise UserError(
                "'%s' is not a valid hostname for the '%s' locker." % (hostname, locker)
            )
    elif hostname.endswith(".mit.edu"):
        reqtype = "moira"
        if hostname.count(".") != 2:
            raise UserError("'%s' has too many dots for a mit.edu hostname." % hostname)
        if not hostname[0].isalpha():
            raise UserError(".mit.edu hostnames must start with a letter.")
        if hostname[-len(".mit.edu") - 1] == "-":
            raise UserError(".mit.edu hostnames cannot end with a dash.")
        if "_" in hostname:
            raise UserError(".mit.edu hostnames cannot contain an underscore.")
        exists = False
        try:
            dns.resolver.query(hostname + ".", 'A')
            exists = True
        except dns.resolver.NXDOMAIN:
            pass
        except dns.exception.Timeout:
            raise
        except dns.resolver.NoAnswer:
            # A record doesn't exist, but other records do
            exists = True
        if exists:
            if hosts.points_at_scripts(hostname) and is_sudoing():
                # It was manually transfered to scripts; if it's not an
                # existing vhost, we good.
                reqtype = "manual"
            else:
                raise UserError(
                    "'%s' already exists. Please choose another name or contact [email protected] if you wish to transfer the hostname to scripts."
                    % hostname
                )

    else:
        reqtype = "external"
        if not hosts.points_at_scripts(hostname):
            # Check if our magic file is there.
            check_file = generate_hostname_check_file(hostname, locker)
            try:
                # If this is a wildcard, pick some random domain to test.
                # We expect that *all* subdomains will match the same host if you're
                # using a wildcard.
                test_hostname = hostname
                if test_hostname[0:2] == "*.":
                    test_hostname = generate_random_hostname() + test_hostname[1:]
                connection = httplib.HTTPConnection(
                    test_hostname, timeout=5
                )  # Shortish timeout - 5 seconds
                connection.request("HEAD", "/%s" % check_file)
                status = connection.getresponse()
                connection.close()
                if status.status != httplib.OK:
                    raise UserError(
                        auth.html(
                            "'%s' does not point at scripts-vhosts. If you want to continue anyway, please create a file called '%s' in the root directory of the site. See <a href='https://scripts.mit.edu/faq/132/can-i-add-a-vhost-before-i-point-my-domain-at-scripts' target='_blank'>the FAQ</a> for more information."
                            % (cgi.escape(hostname), cgi.escape(check_file))
                        )
                    )
            except socket.gaierror:
                raise UserError("'%s' does not exist." % hostname)
            except (httplib.HTTPException, socket.error):
                raise UserError(
                    auth.html(
                        "'%s' does not point at scripts-vhosts, and appears to have no running webserver. Please see <a href='https://scripts.mit.edu/faq/132/can-i-add-a-vhost-before-i-point-my-domain-at-scripts' target='_blank'>the FAQ</a> for more information."
                        % cgi.escape(hostname)
                    )
                )

    return hostname, reqtype
Пример #3
0
def request_vhost(locker, hostname, path, user=None, desc=""):
    """Request hostname as a vhost for the given locker and path.

    Throws a UserError if the request is invalid, otherwise returns
    a human-readable status message and sends a zephyr."""
    locker = locker.encode("utf-8")
    hostname, reqtype = validate_hostname(hostname, locker)
    path = path.encode("utf-8")
    path = validate_path(path)
    message = "The hostname '%s' is now configured." % hostname

    if user is None:
        user = current_user()

    if reqtype == "moira":
        # actually_create_vhost does this check for other reqtypes
        check_if_already_exists(hostname, locker)
        t = queue.Ticket.create(locker, hostname, path, requestor=user, purpose=desc)
        short = hostname[: -len(".mit.edu")]
        out = rt.call(
            "ticket/new",
            Queue="Scripts",
            Subject="scripts-vhosts CNAME request: %s" % short,
            Text="""Heyas,

%(user)s requested %(hostname)s for locker '%(locker)s' path %(path)s.
Go to %(url)s to approve it.

Purpose:
%(desc)s

Love,
~Scripts Pony
"""
            % dict(
                short=short,
                user=user,
                locker=locker,
                hostname=hostname,
                desc=desc,
                path=path,
                url=tg.request.host_url + tg.url("/ticket/%s" % t.id),
            ),
            Requestor=user,
            AdminCc=rt.ponyaddr(),
        )
        for line in out.splitlines():
            if line.startswith("# Ticket ") and line.endswith(" created."):
                t.rtid = int(line[len("# Ticket ") : -len(" created.")])
                break
        else:
            raise RuntimeError("Could not open an RT ticket")
        message = (
            "We will request the hostname %s; mit.edu hostnames generally take 2-3 business days to become active."
            % hostname
        )
    else:
        # Actually create the vhost
        actually_create_vhost(locker, hostname, path)
    if is_sudoing():
        sudobit = "+scripts-pony-acl"
        forbit = " (for %s)" % user
    else:
        sudobit = ""
        forbit = ""
    logmessage = "%s%s requested %s for locker '%s' path '%s'%s (Purpose: %s)" % (
        current_user(),
        sudobit,
        hostname,
        locker,
        path,
        forbit,
        desc,
    )

    log.info(logmessage)
    return message
Пример #4
0
def validate_hostname(hostname, locker):
    hostname = hostname.lower().encode('utf-8')
    if not HOSTNAME_PATTERN.search(hostname):
        if '.' not in hostname:
            raise UserError(
                "'%s' is not an absolute hostname.  Do you mean '%s.mit.edu'?"
                % (hostname, hostname))
        else:
            raise UserError("'%s' is not a valid hostname." % hostname)

    if hostname.endswith(".scripts.mit.edu"):
        reqtype = 'subscripts'
        if not hostname.endswith("." + locker + ".scripts.mit.edu"):
            raise UserError(
                "'%s' is not a valid hostname for the '%s' locker." %
                (hostname, locker))
    elif hostname.endswith(".mit.edu"):
        reqtype = 'moira'
        if hostname.count('.') != 2:
            raise UserError("'%s' has too many dots for a mit.edu hostname." %
                            hostname)
        if not hostname[0].isalpha():
            raise UserError(".mit.edu hostnames must start with a letter.")
        if hostname[-len(".mit.edu") - 1] == '-':
            raise UserError(".mit.edu hostnames cannot end with a dash.")
        if '_' in hostname:
            raise UserError(".mit.edu hostnames cannot contain an underscore.")
        try:
            dns.resolver.query(hostname + '.', 0)
        except dns.resolver.NXDOMAIN:
            pass
        except dns.exception.Timeout:
            raise
        except dns.exception.DNSException:
            if hosts.points_at_scripts(hostname) and is_sudoing():
                # It was manually transfered to scripts; if it's not an
                # existing vhost, we good.
                reqtype = 'manual'
            else:
                raise UserError(
                    "'%s' already exists. Please choose another name or contact [email protected] if you wish to transfer the hostname to scripts."
                    % hostname)
        else:
            raise RuntimeError("DNS query should never return successfully!")
        stella_cmd = subprocess.Popen(
            ["/usr/bin/stella", "-u", "-noauth", hostname],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        out, err = stella_cmd.communicate()
        if stella_cmd.returncode != 1:
            # Then its reserved, deleted, etc.
            status = "Unknown"
            for line in out.split("\n"):
                if "Status:" in line:
                    status = line.split(" ")[-2]
            raise UserError(
                "'%s' is not available; it currently has status %s. Please choose another name or contact [email protected] if you wish to transfer the hostname to scripts."
                % (hostname, status))

    else:
        reqtype = 'external'
        if not hosts.points_at_scripts(hostname):
            # Check if our magic file is there.
            check_file = generate_hostname_check_file(hostname, locker)
            try:
                # If this is a wildcard, pick some random domain to test.
                # We expect that *all* subdomains will match the same host if you're
                # using a wildcard.
                test_hostname = hostname
                if test_hostname[0:2] == '*.':
                    test_hostname = generate_random_hostname(
                    ) + test_hostname[1:]
                connection = httplib.HTTPConnection(
                    test_hostname, timeout=5)  # Shortish timeout - 5 seconds
                connection.request("HEAD", "/%s" % check_file)
                status = connection.getresponse()
                connection.close()
                if status.status != httplib.OK:
                    raise UserError(
                        auth.html(
                            "'%s' does not point at scripts-vhosts. If you want to continue anyway, please create a file called '%s' in the root directory of the site. See <a href='http://scripts.mit.edu/faq/132/can-i-add-a-vhost-before-i-point-my-domain-at-scripts' target='_blank'>the FAQ</a> for more information."
                            % (hostname, check_file)))
            except socket.gaierror:
                raise UserError("'%s' does not exist." % hostname)
            except (httplib.HTTPException, socket.error):
                raise UserError(
                    auth.html(
                        "'%s' does not point at scripts-vhosts, and appears to have no running webserver. Please see <a href='http://scripts.mit.edu/faq/132/can-i-add-a-vhost-before-i-point-my-domain-at-scripts' target='_blank'>the FAQ</a> for more information."
                        % hostname))

    return hostname, reqtype