~launchpad-pqm/launchpad/devel

10637.3.1 by Guilherme Salgado
Use the default python version instead of a hard-coded version
1
#!/usr/bin/python -S
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
2
# pylint: disable-msg=W0403
3
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
4
# Copyright 2010 Canonical Ltd.  This software is licensed under the
5
# GNU Affero General Public License version 3 (see the file LICENSE).
6
#
7
# This code is based on William Grant's make-ubuntu-sane.py script, but
8
# reorganized to fit Launchpad coding guidelines, and extended.  The
9
# code is included under Canonical copyright with his permission
10
# (2010-02-24).
11
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
12
"""Clean up sample data so it will allow Soyuz to run locally.
13
14
DO NOT RUN ON PRODUCTION SYSTEMS.  This script deletes lots of
15
Ubuntu-related data.
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
16
17
This script creates a user "ppa-user" (email ppa-user@example.com,
18
password test) who is able to create PPAs.
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
19
"""
20
21
__metaclass__ = type
22
23
import _pythonpath
24
25
from optparse import OptionParser
26
import re
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
27
import os
28
import subprocess
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
29
import sys
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
30
from textwrap import dedent
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
31
import transaction
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
32
33
from zope.component import getUtility
34
from zope.event import notify
35
from zope.lifecycleevent import ObjectCreatedEvent
36
from zope.security.proxy import removeSecurityProxy
37
38
from storm.store import Store
39
40
from canonical.database.sqlbase import sqlvalues
41
42
from canonical.lp import initZopeless
43
44
from canonical.launchpad.interfaces.launchpad import (
45
    ILaunchpadCelebrities)
46
from canonical.launchpad.scripts import execute_zcml_for_scripts
47
from canonical.launchpad.scripts.logger import logger, logger_options
48
from canonical.launchpad.webapp.interfaces import (
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
49
    IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
50
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
51
from lp.registry.interfaces.codeofconduct import ISignedCodeOfConductSet
10427.4.6 by Jeroen Vermeulen
Final polish. I hope.
52
from lp.registry.interfaces.person import IPersonSet
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
53
from lp.registry.interfaces.series import SeriesStatus
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
54
from lp.registry.model.codeofconduct import SignedCodeOfConduct
11411.6.11 by Julian Edwards
Move SourcePackageFormat
55
from lp.soyuz.enums import SourcePackageFormat
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
56
from lp.soyuz.interfaces.component import IComponentSet
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
57
from lp.soyuz.interfaces.processor import IProcessorFamilySet
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
58
from lp.soyuz.interfaces.section import ISectionSet
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
59
from lp.soyuz.interfaces.sourcepackageformat import (
11411.6.11 by Julian Edwards
Move SourcePackageFormat
60
    ISourcePackageFormatSelectionSet,
61
    )
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
62
from lp.soyuz.model.section import SectionSelection
63
from lp.soyuz.model.component import ComponentSelection
11258.1.13 by Steve Kowalik
Call InitialiseDistroSeries.initialise(), rather than .initialiseFromParent().
64
from lp.soyuz.scripts.initialise_distroseries import InitialiseDistroSeries
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
65
from lp.testing.factory import LaunchpadObjectFactory
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
66
67
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
68
user_name = 'ppa-user'
69
default_email = '%s@example.com' % user_name
70
71
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
72
class DoNotRunOnProduction(Exception):
73
    """Error: do not run this script on production (-like) systems."""
74
75
76
def get_max_id(store, table_name):
77
    """Find highest assigned id in given table."""
78
    max_id = store.execute("SELECT max(id) FROM %s" % table_name).get_one()
79
    if max_id is None:
80
        return None
81
    else:
82
        return max_id[0]
83
84
10373.3.11 by Jeroen Vermeulen
Merge devel
85
def get_store(flavor=MASTER_FLAVOR):
86
    """Obtain an ORM store."""
87
    return getUtility(IStoreSelector).get(MAIN_STORE, flavor)
88
89
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
90
def check_preconditions(options):
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
91
    """Try to ensure that it's safe to run.
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
92
93
    This script must not run on a production server, or anything
94
    remotely like it.
95
    """
10373.3.11 by Jeroen Vermeulen
Merge devel
96
    store = get_store(SLAVE_FLAVOR)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
97
98
    # Just a guess, but dev systems aren't likely to have ids this high
99
    # in this table.  Production data does.
100
    real_data = (get_max_id(store, "TranslationMessage") >= 1000000)
101
    if real_data and not options.force:
102
        raise DoNotRunOnProduction(
103
            "Refusing to delete Ubuntu data unless you --force me.")
104
105
    # For some configs it's just absolutely clear this script shouldn't
106
    # run.  Don't even accept --force there.
107
    forbidden_configs = re.compile('(edge|lpnet|production)')
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
108
    current_config = os.getenv('LPCONFIG', 'an unknown config')
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
109
    if forbidden_configs.match(current_config):
110
        raise DoNotRunOnProduction(
111
            "I won't delete Ubuntu data on %s and you can't --force me."
112
            % current_config)
113
114
115
def parse_args(arguments):
116
    """Parse command-line arguments.
117
118
    :return: (options, args, logger)
119
    """
120
    parser = OptionParser(
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
121
        description="Set up fresh Ubuntu series and %s identity." % user_name)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
122
    parser.add_option('-f', '--force', action='store_true', dest='force',
123
        help="DANGEROUS: run even if the database looks production-like.")
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
124
    parser.add_option('-e', '--email', action='store', dest='email',
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
125
        default=default_email,
126
        help=(
127
            "Email address to use for %s.  Should match your GPG key."
128
            % user_name))
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
129
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
130
    logger_options(parser)
131
132
    options, args = parser.parse_args(arguments)
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
133
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
134
    return options, args, logger(options)
135
136
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
137
def get_person_set():
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
138
    """Return `IPersonSet` utility."""
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
139
    return getUtility(IPersonSet)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
140
141
142
def retire_series(distribution):
143
    """Mark all `DistroSeries` for `distribution` as obsolete."""
144
    for series in distribution.series:
145
        series.status = SeriesStatus.OBSOLETE
146
147
148
def retire_active_publishing_histories(histories, requester):
149
    """Retire all active publishing histories in the given collection."""
150
    # Avoid circular import.
151
    from lp.soyuz.interfaces.publishing import active_publishing_status
152
    for history in histories(status=active_publishing_status):
153
        history.requestDeletion(
154
            requester, "Cleaned up because of missing Librarian files.")
155
156
157
def retire_distro_archives(distribution, culprit):
158
    """Retire all items in `distribution`'s archives."""
159
    for archive in distribution.all_distro_archives:
160
        retire_active_publishing_histories(
161
            archive.getPublishedSources, culprit)
162
        retire_active_publishing_histories(
163
            archive.getAllPublishedBinaries, culprit)
164
165
166
def retire_ppas(distribution):
167
    """Disable all PPAs for `distribution`."""
168
    for ppa in distribution.getAllPPAs():
169
        removeSecurityProxy(ppa).publish = False
170
171
172
def set_lucille_config(distribution):
173
    """Set lucilleconfig on all series of `distribution`."""
174
    for series in distribution.series:
175
        removeSecurityProxy(series).lucilleconfig = '''[publishing]
176
components = main restricted universe multiverse'''
177
178
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
179
def add_architecture(distroseries, architecture_name):
180
    """Add a DistroArchSeries for the given architecture to `distroseries`."""
181
    # Avoid circular import.
182
    from lp.soyuz.model.distroarchseries import DistroArchSeries
183
10373.3.11 by Jeroen Vermeulen
Merge devel
184
    store = get_store(MASTER_FLAVOR)
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
185
    family = getUtility(IProcessorFamilySet).getByName(architecture_name)
186
    archseries = DistroArchSeries(
187
        distroseries=distroseries, processorfamily=family,
188
        owner=distroseries.owner, official=True,
189
        architecturetag=architecture_name)
190
    store.add(archseries)
191
192
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
193
def create_sections(distroseries):
194
    """Set up some sections for `distroseries`."""
195
    section_names = (
196
        'admin', 'cli-mono', 'comm', 'database', 'devel', 'debug', 'doc',
197
        'editors', 'electronics', 'embedded', 'fonts', 'games', 'gnome',
198
        'graphics', 'gnu-r', 'gnustep', 'hamradio', 'haskell', 'httpd',
199
        'interpreters', 'java', 'kde', 'kernel', 'libs', 'libdevel', 'lisp',
200
        'localization', 'mail', 'math', 'misc', 'net', 'news', 'ocaml',
201
        'oldlibs', 'otherosfs', 'perl', 'php', 'python', 'ruby', 'science',
202
        'shells', 'sound', 'tex', 'text', 'utils', 'vcs', 'video', 'web',
203
        'x11', 'xfce', 'zope')
204
    store = Store.of(distroseries)
205
    for section_name in section_names:
206
        section = getUtility(ISectionSet).ensure(section_name)
207
        if section not in distroseries.sections:
208
            store.add(
209
                SectionSelection(distroseries=distroseries, section=section))
210
211
212
def create_components(distroseries, uploader):
213
    """Set up some components for `distroseries`."""
214
    component_names = ('main', 'restricted', 'universe', 'multiverse')
215
    store = Store.of(distroseries)
216
    main_archive = distroseries.distribution.main_archive
217
    for component_name in component_names:
218
        component = getUtility(IComponentSet).ensure(component_name)
219
        if component not in distroseries.components:
220
            store.add(
221
                ComponentSelection(
222
                    distroseries=distroseries, component=component))
223
        main_archive.newComponentUploader(uploader, component)
224
        main_archive.newQueueAdmin(uploader, component)
225
226
227
def create_series(parent, full_name, version, status):
228
    """Set up a `DistroSeries`."""
229
    distribution = parent.distribution
230
    owner = parent.owner
231
    name = full_name.split()[0].lower()
232
    title = "The " + full_name
233
    displayname = full_name.split()[0]
234
    new_series = distribution.newSeries(name=name, title=title,
235
        displayname=displayname, summary='Ubuntu %s is good.' % version,
236
        description='%s is awesome.' % version, version=version,
237
        parent_series=parent, owner=owner)
238
    new_series.status = status
239
    notify(ObjectCreatedEvent(new_series))
240
11258.1.13 by Steve Kowalik
Call InitialiseDistroSeries.initialise(), rather than .initialiseFromParent().
241
    ids = InitialiseDistroSeries(new_series)
242
    ids.initialise()
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
243
    return new_series
244
245
246
def create_sample_series(original_series, log):
247
    """Set up sample `DistroSeries`.
248
249
    :param original_series: The parent for the first new series to be
250
        created.  The second new series will have the first as a parent,
251
        and so on.
252
    """
253
    series_descriptions = [
254
        ('Dapper Drake', SeriesStatus.SUPPORTED, '6.06'),
255
        ('Edgy Eft', SeriesStatus.OBSOLETE, '6.10'),
256
        ('Feisty Fawn', SeriesStatus.OBSOLETE, '7.04'),
257
        ('Gutsy Gibbon', SeriesStatus.OBSOLETE, '7.10'),
258
        ('Hardy Heron', SeriesStatus.SUPPORTED, '8.04'),
259
        ('Intrepid Ibex', SeriesStatus.SUPPORTED, '8.10'),
260
        ('Jaunty Jackalope', SeriesStatus.SUPPORTED, '9.04'),
11091.5.2 by Aaron Bentley
Update soyuz sample data
261
        ('Karmic Koala', SeriesStatus.SUPPORTED, '9.10'),
262
        ('Lucid Lynx', SeriesStatus.CURRENT, '10.04'),
11091.5.6 by Aaron Bentley
Ficks speling
263
        ('Maverick Meerkat', SeriesStatus.DEVELOPMENT, '10.10'),
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
264
        ]
265
266
    parent = original_series
267
    for full_name, status, version in series_descriptions:
268
        log.info('Creating %s...' % full_name)
269
        parent = create_series(parent, full_name, version, status)
270
271
272
def clean_up(distribution, log):
273
    # First we eliminate all active publishings in the Ubuntu main archives.
274
    # None of the librarian files exist, so it kills the publisher.
275
276
    # Could use IPublishingSet.requestDeletion() on the published sources to
277
    # get rid of the binaries too, but I don't trust that there aren't
278
    # published binaries without corresponding sources.
279
280
    log.info("Deleting all items in official archives...")
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
281
    retire_distro_archives(distribution, get_person_set().getByName('name16'))
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
282
283
    # Disable publishing of all PPAs, as they probably have broken
284
    # publishings too.
285
    log.info("Disabling all PPAs...")
286
    retire_ppas(distribution)
287
288
    retire_series(distribution)
289
290
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
291
def set_source_package_format(distroseries):
292
    """Register a series' source package format selection."""
293
    utility = getUtility(ISourcePackageFormatSelectionSet)
294
    format = SourcePackageFormat.FORMAT_1_0
295
    if utility.getBySeriesAndFormat(distroseries, format) is None:
296
        utility.add(distroseries, format)
297
298
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
299
def populate(distribution, parent_series_name, uploader_name, options, log):
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
300
    """Set up sample data on `distribution`."""
301
    parent_series = distribution.getSeries(parent_series_name)
302
303
    # Set up lucilleconfig on all series.  The sample data lacks this.
304
    log.info("Setting lucilleconfig...")
305
    set_lucille_config(distribution)
306
307
    log.info("Configuring sections...")
308
    create_sections(parent_series)
10373.3.9 by Jeroen Vermeulen
Always include amd64 support.
309
    add_architecture(parent_series, 'amd64')
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
310
311
    log.info("Configuring components and permissions...")
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
312
    uploader = get_person_set().getByName(uploader_name)
313
    create_components(parent_series, uploader)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
314
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
315
    set_source_package_format(parent_series)
316
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
317
    create_sample_series(parent_series, log)
318
319
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
320
def sign_code_of_conduct(person, log):
321
    """Sign Ubuntu Code of Conduct for `person`, if necessary."""
322
    if person.is_ubuntu_coc_signer:
323
        # Already signed.
324
        return
325
326
    log.info("Signing Ubuntu code of conduct.")
327
    signedcocset = getUtility(ISignedCodeOfConductSet)
328
    person_id = person.id
329
    if signedcocset.searchByUser(person_id).count() == 0:
330
        fake_gpg_key = LaunchpadObjectFactory().makeGPGKey(person)
331
        Store.of(person).add(SignedCodeOfConduct(
332
            owner=person, signingkey=fake_gpg_key,
333
            signedcode="Normally a signed CoC would go here.", active=True))
334
335
336
def create_ppa_user(username, options, approver, log):
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
337
    """Create new user, with password "test," and sign code of conduct."""
338
    person = get_person_set().getByName(username)
339
    if person is None:
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
340
        have_email = (options.email != default_email)
341
        command_line = [
342
            'utilities/make-lp-user',
343
            username,
344
            'ubuntu-team'
345
            ]
346
        if have_email:
347
            command_line += ['--email', options.email]
348
349
        pipe = subprocess.Popen(command_line, stderr=subprocess.PIPE)
350
        stdout, stderr = pipe.communicate()
351
        if stderr != '':
352
            print stderr
353
        if pipe.returncode != 0:
354
            sys.exit(2)
355
356
    transaction.commit()
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
357
10427.4.6 by Jeroen Vermeulen
Final polish. I hope.
358
    person = getUtility(IPersonSet).getByName(username)
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
359
    sign_code_of_conduct(person, log)
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
360
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
361
    return person
362
363
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
364
def create_ppa(distribution, person, name):
365
    """Create a PPA for `person`."""
10373.3.12 by Jeroen Vermeulen
Set external dependencies.
366
    ppa = LaunchpadObjectFactory().makeArchive(
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
367
        distribution=distribution, owner=person, name=name, virtualized=False,
368
        description="Automatically created test PPA.")
369
10373.3.12 by Jeroen Vermeulen
Set external dependencies.
370
    series_name = distribution.currentseries.name
371
    ppa.external_dependencies = (
372
        "deb http://archive.ubuntu.com/ubuntu %s "
373
        "main restricted universe multiverse\n") % series_name
374
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
375
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
376
def main(argv):
377
    options, args, log = parse_args(argv[1:])
378
379
    execute_zcml_for_scripts()
380
    txn = initZopeless(dbuser='launchpad')
381
382
    check_preconditions(options.force)
383
384
    ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
385
    clean_up(ubuntu, log)
386
387
    # Use Hoary as the root, as Breezy and Grumpy are broken.
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
388
    populate(ubuntu, 'hoary', 'ubuntu-team', options, log)
389
390
    admin = get_person_set().getByName('name16')
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
391
    person = create_ppa_user(user_name, options, admin, log)
392
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
393
    create_ppa(ubuntu, person, 'test-ppa')
10303.1.9 by Gary Poster
merge with devel; it has been awhile!
394
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
395
    txn.commit()
10373.3.8 by Jeroen Vermeulen
Moved instructions to the very end again.
396
    log.info("Done.")
397
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
398
    print dedent("""
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
399
        Now start your local Launchpad with "make run_codehosting" and log
400
        into https://launchpad.dev/ as "%(email)s" with "test" as the
401
        password.
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
402
        Your user name will be %(user_name)s."""
403
        % {
404
            'email': options.email,
405
            'user_name': user_name,
406
            })
407
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
408
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
409
if __name__ == "__main__":
410
    main(sys.argv)