new_security_install.py 6.6 KB
Newer Older
1 2
#!/usr/bin/env python

J
Joerg Jaspert 已提交
3 4 5 6 7 8 9
"""
Do whatever is needed to get a security upload released

@contact: Debian FTP Master <ftpmaster@debian.org>
@copyright: 2010 Joerg Jaspert <joerg@debian.org>
@license: GNU General Public License version 2 or later
"""
10 11 12 13 14 15

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

J
Joerg Jaspert 已提交
16 17 18 19
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
20 21 22

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
J
Joerg Jaspert 已提交
23 24 25 26
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

################################################################################

27 28 29

################################################################################

B
Bastian Blank 已提交
30 31
from __future__ import print_function

J
Joerg Jaspert 已提交
32 33 34 35 36
import os
import sys
import time
import apt_pkg
import commands
J
Joerg Jaspert 已提交
37 38
import errno
import fcntl
39

40
from daklib import daklog
41
from daklib import utils
J
Joerg Jaspert 已提交
42
from daklib.dbconn import *
43
from daklib.regexes import re_taint_free
J
Joerg Jaspert 已提交
44
from daklib.config import Config
45 46 47

Options = None
Logger = None
J
Joerg Jaspert 已提交
48
Queue = None
49 50
changes = []

51

J
Joerg Jaspert 已提交
52
def usage():
B
Bastian Blank 已提交
53
    print("""Usage: dak security-install [OPTIONS] changesfiles
J
Joerg Jaspert 已提交
54
Do whatever there is to do for a security release
55

J
Joerg Jaspert 已提交
56 57 58
    -h, --help                 show this help and exit
    -n, --no-action            don't commit changes
    -s, --sudo                 dont bother, used internally
59

B
Bastian Blank 已提交
60
""")
J
Joerg Jaspert 已提交
61
    sys.exit()
62 63 64 65


def spawn(command):
    if not re_taint_free.match(command):
66
        utils.fubar("Invalid character in \"%s\"." % (command))
67 68

    if Options["No-Action"]:
B
Bastian Blank 已提交
69
        print("[%s]" % (command))
70 71 72
    else:
        (result, output) = commands.getstatusoutput(command)
        if (result != 0):
73
            utils.fubar("Invocation of '%s' failed:\n%s\n" % (command, output), result)
74 75 76 77 78 79 80 81

##################### ! ! ! N O T E ! ! !  #####################
#
# These functions will be reinvoked by semi-priveleged users, be careful not
# to invoke external programs that will escalate privileges, etc.
#
##################### ! ! ! N O T E ! ! !  #####################

82

83 84
def sudo(arg, fn, exit):
    if Options["Sudo"]:
85
        os.spawnl(os.P_WAIT, "/usr/bin/sudo", "/usr/bin/sudo", "-u", "dak", "-H",
86
                  "/usr/local/bin/dak", "new-security-install", "-" + arg)
87 88 89 90 91
    else:
        fn()
    if exit:
        quit()

92

93 94
def do_Approve():
    sudo("A", _do_Approve, True)
95 96


97
def _do_Approve():
B
Bastian Blank 已提交
98
    print("Locking unchecked")
B
Bastian Blank 已提交
99
    with os.fdopen(os.open('/srv/security-master.debian.org/lock/unchecked.lock', os.O_CREAT | os.O_RDWR), 'r') as lock_fd:
100 101 102 103 104 105
        while True:
            try:
                fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
                break
            except IOError as e:
                if e.errno in (errno.EACCES, errno.EAGAIN):
B
Bastian Blank 已提交
106
                    print("Another process keeping the unchecked lock, waiting.")
107 108 109 110 111
                    time.sleep(10)
                else:
                    raise

        # 1. Install accepted packages
B
Bastian Blank 已提交
112
        print("Installing accepted packages into security archive")
113 114
        for queue_name in ("embargoed",):
            spawn("dak process-policy {0}".format(queue_name))
115 116

    # 2. Run all the steps that are needed to publish the changed archive
B
Bastian Blank 已提交
117
    print("Doing loadsa stuff in the archive, will take time, please be patient")
J
Joerg Jaspert 已提交
118 119 120
    os.environ['configdir'] = '/srv/security-master.debian.org/dak/config/debian-security'
    spawn("/srv/security-master.debian.org/dak/config/debian-security/cronscript unchecked-dinstall")

B
Bastian Blank 已提交
121
    print("Triggering metadata export for packages.d.o and other consumers")
J
Joerg Jaspert 已提交
122
    spawn("/srv/security-master.debian.org/dak/config/debian-security/export.sh")
123

J
Joerg Jaspert 已提交
124 125
########################################################################
########################################################################
126

127

J
Joerg Jaspert 已提交
128 129 130
def main():
    global Options, Logger, Queue, changes
    cnf = Config()
131

J
Joerg Jaspert 已提交
132 133 134
    Arguments = [('h', "Help",      "Security::Options::Help"),
                 ('n', "No-Action", "Security::Options::No-Action"),
                 ('c', 'Changesfile', "Security::Options::Changesfile"),
J
Joerg Jaspert 已提交
135 136
                 ('s', "Sudo", "Security::Options::Sudo"),
                 ('A', "Approve", "Security::Options::Approve")
J
Joerg Jaspert 已提交
137
                 ]
138

J
Joerg Jaspert 已提交
139
    for i in ["Help", "No-Action", "Changesfile", "Sudo", "Approve"]:
140 141 142
        key = "Security::Options::%s" % i
        if key not in cnf:
            cnf[key] = ""
143

144
    changes_files = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
145

146
    Options = cnf.subtree("Security::Options")
J
Joerg Jaspert 已提交
147 148
    if Options['Help']:
        usage()
149

150
    changesfiles = {}
J
Joerg Jaspert 已提交
151 152 153
    for a in changes_files:
        if not a.endswith(".changes"):
            utils.fubar("not a .changes file: %s" % (a))
154
        changesfiles[a] = 1
J
Joerg Jaspert 已提交
155
    changes = changesfiles.keys()
156

J
Joerg Jaspert 已提交
157 158
    username = utils.getusername()
    if username != "dak":
B
Bastian Blank 已提交
159
        print("Non-dak user: %s" % username)
J
Joerg Jaspert 已提交
160 161 162 163 164 165
        Options["Sudo"] = "y"

    if Options["No-Action"]:
        Options["Sudo"] = ""

    if not Options["Sudo"] and not Options["No-Action"]:
166
        Logger = daklog.Logger("security-install")
J
Joerg Jaspert 已提交
167 168 169 170

    session = DBConn().session()

    # If we call ourselve to approve, we do just that and exit
171 172
    if Options["Approve"]:
        do_Approve()
J
Joerg Jaspert 已提交
173 174 175 176 177 178 179
        sys.exit()

    if len(changes) == 0:
        utils.fubar("Need changes files as arguments")

    # Yes, we could do this inside do_Approve too. But this way we see who exactly
    # called it (ownership of the file)
180

181
    acceptfiles = {}
182
    for change in changes:
183
        dbchange = get_dbchange(os.path.basename(change), session)
184
        # strip epoch from version
185
        version = dbchange.version
186
        version = version[(version.find(':') + 1):]
187 188
        # strip possible version from source (binNMUs)
        source = dbchange.source.split(None, 1)[0]
189 190
        acceptfilename = "%s/COMMENTS/ACCEPT.%s_%s" % (os.path.dirname(os.path.abspath(changes[0])), source, version)
        acceptfiles[acceptfilename] = 1
191

B
Bastian Blank 已提交
192
    print("Would create %s now and then go on to accept this package, if you allow me to." % (acceptfiles.keys()))
J
Joerg Jaspert 已提交
193 194
    if Options["No-Action"]:
        sys.exit(0)
195 196
    else:
        raw_input("Press Enter to continue")
197 198 199 200 201 202

    for acceptfilename in acceptfiles.keys():
        accept_file = file(acceptfilename, "w")
        accept_file.write("OK\n")
        accept_file.close()

J
Joerg Jaspert 已提交
203
    do_Approve()
204 205 206 207


if __name__ == '__main__':
    main()