This file is indexed.

/usr/bin/skytools_upgrade3 is in skytools3 3.2.6-4.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/python

"""Upgrade script for versioned schemas."""

usage = """
    %prog [--user=U] [--host=H] [--port=P] --all
    %prog [--user=U] [--host=H] [--port=P] DB1 [ DB2 ... ]\
"""

import sys, os, re, optparse

import pkgloader
pkgloader.require('skytools', '3.0')
import skytools
from skytools.natsort import natsort_key


# schemas, where .upgrade.sql is enough
AUTO_UPGRADE = ('pgq', 'pgq_node', 'pgq_coop', 'londiste', 'pgq_ext')

# fetch list of databases
DB_LIST = "select datname from pg_database "\
          " where not datistemplate and datallowconn "\
          " order by 1"

# dont support upgrade from 2.x (yet?)
version_list = [
    # schema, ver, filename, recheck_func
    ['pgq', '3.0', None, None],
    ['londiste', '3.0', None, None],
    ['pgq_ext', '2.1', None, None],
]


def is_version_ge(a, b):
    """Return True if a is greater or equal than b."""
    va = natsort_key(a)
    vb = natsort_key(b)
    return va >= vb

def is_version_gt(a, b):
    """Return True if a is greater than b."""
    va = natsort_key(a)
    vb = natsort_key(b)
    return va > vb


def check_version(curs, schema, new_ver_str, recheck_func=None, force_gt=False):
    funcname = "%s.version" % schema
    if not skytools.exists_function(curs, funcname, 0):
        if recheck_func is not None:
            return recheck_func(curs), 'NULL'
        else:
            return 0, 'NULL'
    q = "select %s()" % funcname
    curs.execute(q)
    old_ver_str = curs.fetchone()[0]
    if force_gt:
        ok = is_version_gt(old_ver_str, new_ver_str)
    else:
        ok = is_version_ge(old_ver_str, new_ver_str)
    return ok, old_ver_str


class DbUpgrade(skytools.DBScript):
    """Upgrade all Skytools schemas in Postgres cluster."""

    def upgrade(self, dbname, db):
        """Upgrade all schemas in single db."""

        curs = db.cursor()
        ignore = {}
        for schema, ver, fn, recheck_func in version_list:
            # skip schema?
            if schema in ignore:
                continue
            if not skytools.exists_schema(curs, schema):
                ignore[schema] = 1
                continue

            # new enough?
            ok, oldver = check_version(curs, schema, ver, recheck_func, self.options.force)
            if ok:
                continue

            # too old schema, no way to upgrade
            if fn is None:
                self.log.info('%s: Cannot upgrade %s, too old version', dbname, schema)
                ignore[schema] = 1
                continue

            if self.options.not_really:
                self.log.info ("%s: Would upgrade '%s' version %s to %s", dbname, schema, oldver, ver)
                continue

            curs = db.cursor()
            curs.execute('begin')
            self.log.info("%s: Upgrading '%s' version %s to %s", dbname, schema, oldver, ver)
            skytools.installer_apply_file(db, fn, self.log)
            curs.execute('commit')

    def work(self):
        """Loop over databases."""

        self.set_single_loop(1)

        self.load_cur_versions()

        # loop over all dbs
        dblst = self.args
        if self.options.all:
            db = self.connect_db('postgres')
            curs = db.cursor()
            curs.execute(DB_LIST)
            dblst = []
            for row in curs.fetchall():
                dblst.append(row[0])
            self.close_database('db')
        elif not dblst:
            raise skytools.UsageError('Give --all or list of database names on command line')

        # loop over connstrs
        for dbname in dblst:
            if self.last_sigint:
                break
            self.log.info("%s: connecting", dbname)
            db = self.connect_db(dbname)
            self.upgrade(dbname, db)
            self.close_database('db')

    def load_cur_versions(self):
        """Load current version numbers from .upgrade.sql files."""

        vrc = re.compile(r"^ \s+ return \s+ '([0-9.]+)';", re.X | re.I | re.M)
        for s in AUTO_UPGRADE:
            fn = '%s.upgrade.sql' % s
            fqfn = skytools.installer_find_file(fn)
            try:
                f = open(fqfn, 'r')
            except IOError, d:
                raise skytools.UsageError('%s: cannot find upgrade file: %s [%s]' % (s, fqfn, str(d)))

            sql = f.read()
            f.close()
            m = vrc.search(sql)
            if not m:
                raise skytools.UsageError('%s: failed to detect version' % fqfn)

            ver = m.group(1)
            cur = [s, ver, fn, None]
            self.log.info("Loaded %s %s from %s", s, ver, fqfn)
            version_list.append(cur)

    def connect_db(self, dbname):
        """Create connect string, then connect."""

        elems = ["dbname='%s'" % dbname]
        if self.options.host:
            elems.append("host='%s'" % self.options.host)
        if self.options.port:
            elems.append("port='%s'" % self.options.port)
        if self.options.user:
            elems.append("user='%s'" % self.options.user)
        cstr = ' '.join(elems)
        return self.get_database('db', connstr = cstr, autocommit = 1)

    def init_optparse(self, parser=None):
        """Setup command-line flags."""
        p = skytools.DBScript.init_optparse(self, parser)
        p.set_usage(usage)
        g = optparse.OptionGroup(p, "options for skytools_upgrade")
        g.add_option("--all", action="store_true", help = 'upgrade all databases')
        g.add_option("--not-really", action = "store_true", dest = "not_really",
                     default = False, help = "don't actually do anything")
        g.add_option("--user", help = 'username to use')
        g.add_option("--host", help = 'hostname to use')
        g.add_option("--port", help = 'port to use')
        g.add_option("--force", action = "store_true",
                     help = 'upgrade even if schema versions are new enough')
        p.add_option_group(g)
        return p

    def load_config(self):
        """Disable config file."""
        return skytools.Config(self.service_name, None,
                user_defs = {'use_skylog': '0', 'job_name': 'db_upgrade'})

if __name__ == '__main__':
    script = DbUpgrade('skytools_upgrade', sys.argv[1:])
    script.start()