[server/migractions] simplify the Migration Handler entry point

There is no need to entertain numerous ways to create a migration handler. We move .set_cnx to cwctl.admincnx, which given a repository, will return an admin cnx.

Moreover, we use the repoapi.get_repository to get repositories.

Related to #3933480.

authorAurelien Campeas <aurelien.campeas@logilab.fr>
changeset41a817cd961c
branchdefault
phasedraft
hiddenyes
parent revision#6454ee8f2137 [connection] remove a dead counter
child revision<not specified>
files modified by this revision
cubicweb/cwctl.py
cubicweb/devtools/testlib.py
cubicweb/server/__init__.py
cubicweb/server/migractions.py
cubicweb/server/serverconfig.py
cubicweb/server/serverctl.py
cubicweb/server/test/unittest_migractions.py
cubicweb/test/unittest_cwctl.py
# HG changeset patch
# User Aurelien Campeas <aurelien.campeas@logilab.fr>
# Date 1404908797 -7200
# Wed Jul 09 14:26:37 2014 +0200
# Node ID 41a817cd961ca2cc8f0a4c925cc8b13f9f24de2a
# Parent 6454ee8f213764a10975be046e7f52abaf4c96ba
[server/migractions] simplify the Migration Handler entry point

There is no need to entertain numerous ways to create a migration
handler. We move .set_cnx to cwctl.admincnx, which given a repository,
will return an admin cnx.

Moreover, we use the repoapi.get_repository to get repositories.

Related to #3933480.

diff --git a/cubicweb/cwctl.py b/cubicweb/cwctl.py
@@ -719,12 +719,12 @@
1          config.verbosity = self.config.verbosity
2          set_sources_mode = getattr(config, 'set_sources_mode', None)
3          if set_sources_mode is not None:
4              set_sources_mode(self.config.ext_sources or ('migration',))
5          # get instance and installed versions for the server and the componants
6 -        mih = config.migration_handler()
7 -        repo = mih.repo
8 +        repo = config.repository()
9 +        mih = config.migration_handler(admincnx(appid))
10          vcconf = repo.get_versions()
11          helper = self.config_helper(config, required=False)
12          if self.config.force_cube_version:
13              for cube, version in self.config.force_cube_version.items():
14                  vcconf[cube] = Version(version)
@@ -877,11 +877,11 @@
15              sources = ('system',)
16          else:
17              sources = ('all',)
18          config.set_sources_mode(sources)
19          config.repairing = self.config.force
20 -        mih = config.migration_handler()
21 +        mih = config.migration_handler(cnx)
22          return mih, lambda: mih.shutdown()
23 
24      def run(self, args):
25          appuri = args.pop(0)
26          if self.config.repo_uri:
@@ -897,12 +897,12 @@
27                      if args:
28                          # use cmdline parser to access left/right attributes only
29                          # remember that usage requires instance appid as first argument
30                          scripts, args = self.cmdline_parser.largs[1:], self.cmdline_parser.rargs
31                          for script in scripts:
32 -                                mih.cmd_process_script(script, scriptargs=args)
33 -                                mih.commit()
34 +                            mih.cmd_process_script(script, scriptargs=args)
35 +                            mih.commit()
36                      else:
37                          mih.interactive_shell()
38          finally:
39              shutdown_callback()
40 
diff --git a/cubicweb/devtools/testlib.py b/cubicweb/devtools/testlib.py
@@ -271,12 +271,11 @@
41 
42      @contextmanager
43      def shell(self):
44          from cubicweb.server.migractions import ServerMigrationHelper
45          with self._session.new_cnx() as cnx:
46 -            mih = ServerMigrationHelper(None, repo=self._repo, cnx=cnx,
47 -                                        interactive=False,
48 +            mih = ServerMigrationHelper(None, cnx=cnx, interactive=False,
49                                          # hack so it don't try to load fs schema
50                                          schema=1)
51              yield mih
52              cnx.commit()
53 
diff --git a/cubicweb/server/__init__.py b/cubicweb/server/__init__.py
@@ -301,12 +301,11 @@
54      # schema to `initialize_schema` above since it will initialize .eid attribute of schema elements
55      schema = repo.schema
56      with connect(repo, login, password=pwd) as cnx:
57          with cnx.security_enabled(False, False):
58              repo.system_source.eid = ssource.eid # redo this manually
59 -            handler = config.migration_handler(schema, interactive=False,
60 -                                               cnx=cnx, repo=repo)
61 +            handler = config.migration_handler(cnx, schema, interactive=False)
62              # serialize the schema
63              initialize_schema(config, schema, handler)
64              # yoo !
65              cnx.commit()
66              repo.system_source.init_creating()
diff --git a/cubicweb/server/migractions.py b/cubicweb/server/migractions.py
@@ -84,40 +84,26 @@
67  class ServerMigrationHelper(MigrationHelper):
68      """specific migration helper for server side migration scripts,
69      providing actions related to schema/data migration
70      """
71 
72 -    def __init__(self, config, schema, interactive=True,
73 -                 repo=None, cnx=None, verbosity=1, connect=True):
74 -        MigrationHelper.__init__(self, config, interactive, verbosity)
75 -        if not interactive:
76 -            assert cnx
77 -            assert repo
78 -        if cnx is not None:
79 -            assert repo
80 -            self.cnx = cnx
81 -            self.repo = repo
82 -            self.session = cnx.session
83 -        elif connect:
84 -            self.repo = config.repository()
85 -            self.set_cnx()
86 -        else:
87 -            self.session = None
88 -        # no config on shell to a remote instance
89 -        if config is not None and (cnx or connect):
90 -            repo = self.repo
91 -            # register a hook to clear our group_mapping cache and the
92 -            # self._synchronized set when some group is added or updated
93 -            ClearGroupMap.mih = self
94 -            ClearGroupMap.mih_register(repo)
95 -            CW_EVENT_MANAGER.bind('after-registry-reload',
96 -                                  ClearGroupMap.mih_register, repo)
97 -            # notify we're starting maintenance (called instead of server_start
98 -            # which is called on regular start
99 -            repo.hm.call_hooks('server_maintenance', repo=repo)
100 +    def __init__(self, config, cnx, schema=None, interactive=True, verbosity=1):
101 +        super(ServerMigrationHelper, self).__init__(config, interactive, verbosity)
102 +        self.cnx = cnx
103 +        self.repo = cnx.session.repo
104 +        # register a hook to clear our group_mapping cache and the
105 +        # self._synchronized set when some group is added or updated
106 +        ClearGroupMap.mih = self
107 +        ClearGroupMap.mih_register(self.repo)
108 +        CW_EVENT_MANAGER.bind('after-registry-reload',
109 +                              ClearGroupMap.mih_register, self.repo)
110 +        # notify we're starting maintenance (called instead of server_start
111 +        # which is called on regular start)
112 +        self.repo.hm.call_hooks('server_maintenance', repo=self.repo)
113          if not schema and not config.quick_start:
114 -            insert_lperms = self.repo.get_versions()['cubicweb'] < (3, 14, 0) and 'localperms' in config.available_cubes()
115 +            insert_lperms = (self.repo.get_versions()['cubicweb'] < (3, 14, 0) and
116 +                             'localperms' in config.available_cubes())
117              if insert_lperms:
118                  cubes = config._cubes
119                  config._cubes += ('localperms',)
120              try:
121                  schema = config.load_schema(expand_cubes=True)
@@ -127,35 +113,10 @@
122          self.fs_schema = schema
123          self._synchronized = set()
124 
125      # overriden from base MigrationHelper ######################################
126 
127 -    def set_cnx(self):
128 -        try:
129 -            login = self.repo.config.default_admin_config['login']
130 -            pwd = self.repo.config.default_admin_config['password']
131 -        except KeyError:
132 -            login, pwd = manager_userpasswd()
133 -        while True:
134 -            try:
135 -                self.cnx = repoapi.connect(self.repo, login, password=pwd)
136 -                if not 'managers' in self.cnx.user.groups:
137 -                    print('migration need an account in the managers group')
138 -                else:
139 -                    break
140 -            except AuthenticationError:
141 -                print('wrong user/password')
142 -            except (KeyboardInterrupt, EOFError):
143 -                print('aborting...')
144 -                sys.exit(0)
145 -            try:
146 -                login, pwd = manager_userpasswd()
147 -            except (KeyboardInterrupt, EOFError):
148 -                print('aborting...')
149 -                sys.exit(0)
150 -        self.session = self.repo._get_session(self.cnx.sessionid)
151 -
152      def cube_upgraded(self, cube, version):
153          self.cmd_set_property('system.version.%s' % cube.lower(),
154                                text_type(version))
155          self.commit()
156 
@@ -188,11 +149,10 @@
157 
158      # server specific migration methods ########################################
159 
160      def backup_database(self, backupfile=None, askconfirm=True, format='native'):
161          config = self.config
162 -        repo = self.repo
163          # paths
164          timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
165          instbkdir = osp.join(config.appdatahome, 'backup')
166          if not osp.exists(instbkdir):
167              os.makedirs(instbkdir)
@@ -207,11 +167,11 @@
168              print('-> no backup done.')
169              return
170          open(backupfile,'w').close() # kinda lock
171          os.chmod(backupfile, 0o600)
172          # backup
173 -        source = repo.system_source
174 +        source = self.repo.system_source
175          tmpdir = tempfile.mkdtemp()
176          try:
177              failed = False
178              try:
179                  source.backup(osp.join(tmpdir, source.uri), self.confirm, format=format)
@@ -222,20 +182,20 @@
180                  else:
181                      failed = True
182              with open(osp.join(tmpdir, 'format.txt'), 'w') as format_file:
183                  format_file.write('%s\n' % format)
184              with open(osp.join(tmpdir, 'versions.txt'), 'w') as version_file:
185 -                versions = repo.get_versions()
186 +                versions = self.repo.get_versions()
187                  for cube, version in versions.items():
188                      version_file.write('%s %s\n' % (cube, version))
189              if not failed:
190                  bkup = tarfile.open(backupfile, 'w|gz')
191                  for filename in os.listdir(tmpdir):
192                      bkup.add(osp.join(tmpdir, filename), filename)
193                  bkup.close()
194                  # call hooks
195 -                repo.hm.call_hooks('server_backup', repo=repo, timestamp=timestamp)
196 +                self.repo.hm.call_hooks('server_backup', repo=self.repo, timestamp=timestamp)
197                  # done
198                  print('-> backup file',  backupfile)
199          finally:
200              shutil.rmtree(tmpdir)
201 
@@ -266,21 +226,21 @@
202                  written_format = format_file.readline().strip()
203                  if written_format in ('portable', 'native'):
204                      format = written_format
205          self.config.init_cnxset_pool = False
206          repo = self.repo = self.config.repository()
207 -        source = repo.system_source
208 +        source = self.repo.system_source
209          try:
210              source.restore(osp.join(tmpdir, source.uri), self.confirm, drop, format)
211          except Exception as exc:
212              print('-> error trying to restore %s [%s]' % (source.uri, exc))
213              if not self.confirm('Continue anyway?', default='n'):
214                  raise SystemExit(1)
215          shutil.rmtree(tmpdir)
216          # call hooks
217 -        repo.init_cnxset_pool()
218 -        repo.hm.call_hooks('server_restore', repo=repo, timestamp=backupfile)
219 +        self.repo.init_cnxset_pool()
220 +        self.repo.hm.call_hooks('server_restore', repo=self.repo, timestamp=backupfile)
221          print('-> database restored.')
222 
223      def commit(self):
224          self.cnx.commit()
225 
diff --git a/cubicweb/server/serverconfig.py b/cubicweb/server/serverconfig.py
@@ -337,14 +337,12 @@
226 
227      sources_mode = None
228      def set_sources_mode(self, sources):
229          self.sources_mode = sources
230 
231 -    def migration_handler(self, schema=None, interactive=True,
232 -                          cnx=None, repo=None, connect=True, verbosity=None):
233 +    def migration_handler(self, cnx, schema=None, interactive=True, verbosity=None):
234          """return a migration handler instance"""
235          from cubicweb.server.migractions import ServerMigrationHelper
236          if verbosity is None:
237              verbosity = getattr(self, 'verbosity', 0)
238 -        return ServerMigrationHelper(self, schema, interactive=interactive,
239 -                                     cnx=cnx, repo=repo, connect=connect,
240 -                                     verbosity=verbosity)
241 +        return ServerMigrationHelper(self, cnx, schema=schema,
242 +                                     interactive=interactive, verbosity=verbosity)
diff --git a/cubicweb/server/serverctl.py b/cubicweb/server/serverctl.py
@@ -35,10 +35,11 @@
243 
244  from logilab.database import get_db_helper, get_connection
245 
246  from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
247  from cubicweb.toolsutils import Command, CommandHandler, underline_title
248 +from cubicweb.utils import admincnx
249  from cubicweb.cwctl import CWCTL, check_options_consistency, ConfigureInstanceCommand
250  from cubicweb.server import SOURCE_TYPES
251  from cubicweb.server.serverconfig import (
252      USER_OPTIONS, ServerConfiguration, SourceConfiguration,
253      ask_source_config, generate_source_config)
@@ -687,20 +688,22 @@
254 
255 
256  def _local_dump(appid, output, format='native'):
257      config = ServerConfiguration.config_for(appid)
258      config.quick_start = True
259 -    mih = config.migration_handler(verbosity=1)
260 +    cnx = admincnx(appid)
261 +    mih = config.migration_handler(cnx, connect=False, verbosity=1)
262      mih.backup_database(output, askconfirm=False, format=format)
263      mih.shutdown()
264 
265 
266  def _local_restore(appid, backupfile, drop, format='native'):
267      config = ServerConfiguration.config_for(appid)
268      config.verbosity = 1  # else we won't be asked for confirmation on problems
269      config.quick_start = True
270 -    mih = config.migration_handler(connect=False, verbosity=1)
271 +    cnx = admincnx(appid)
272 +    mih = config.migration_handler(cnx, connect=False, verbosity=1)
273      mih.restore_database(backupfile, drop, askconfirm=False, format=format)
274      repo = mih.repo
275      # version of the database
276      dbversions = repo.get_versions()
277      mih.shutdown()
diff --git a/cubicweb/server/test/unittest_migractions.py b/cubicweb/server/test/unittest_migractions.py
@@ -89,13 +89,11 @@
278          self.repo.vreg['etypes'].clear_caches()
279 
280      @contextmanager
281      def mh(self):
282          with self.admin_access.repo_cnx() as cnx:
283 -            yield cnx, ServerMigrationHelper(self.repo.config, migrschema,
284 -                                             repo=self.repo, cnx=cnx,
285 -                                             interactive=False)
286 +            yield cnx, ServerMigrationHelper(self.repo.config, cnx, migrschema, interactive=False)
287 
288      def table_sql(self, mh, tablename):
289          result = mh.sqlexec("SELECT table_name FROM information_schema.tables WHERE LOWER(table_name)=%(table)s",
290                              {'table': tablename.lower()})
291          if result:
diff --git a/cubicweb/test/unittest_cwctl.py b/cubicweb/test/unittest_cwctl.py
@@ -46,11 +46,11 @@
292  class CubicWebShellTC(CubicWebTC):
293 
294      def test_process_script_args_context(self):
295          repo = self.repo
296          with self.admin_access.repo_cnx() as cnx:
297 -            mih = ServerMigrationHelper(None, repo=repo, cnx=cnx,
298 +            mih = ServerMigrationHelper(None, cnx=cnx,
299                                          interactive=False,
300                                          # hack so it don't try to load fs schema
301                                          schema=1)
302              scripts = {'script1.py': list(),
303                         'script2.py': ['-v'],