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