doc/book/devrepo/migration.rst
changeset 10491 c67bcee93248
parent 9304 ff61b10e7415
child 10994 ebd586aa5b00
equal deleted inserted replaced
10490:76ab3c71aff2 10491:c67bcee93248
       
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 .. _migration:
       
     4 
       
     5 Migration
       
     6 =========
       
     7 
       
     8 One of the main design goals of *CubicWeb* was to support iterative and agile
       
     9 development. For this purpose, multiple actions are provided to facilitate the
       
    10 improvement of an instance, and in particular to handle the changes to be
       
    11 applied to the data model, without loosing existing data.
       
    12 
       
    13 The current version of a cube (and of cubicweb itself) is provided in the file
       
    14 `__pkginfo__.py` as a tuple of 3 integers.
       
    15 
       
    16 Migration scripts management
       
    17 ----------------------------
       
    18 
       
    19 Migration scripts has to be located in the directory `migration` of your
       
    20 cube and named accordingly:
       
    21 
       
    22 ::
       
    23 
       
    24   <version n° X.Y.Z>[_<description>]_<mode>.py
       
    25 
       
    26 in which :
       
    27 
       
    28 * X.Y.Z is the model version number to which the script enables to migrate.
       
    29 
       
    30 * *mode* (between the last "_" and the extension ".py") is used for
       
    31   distributed installation. It indicates to which part
       
    32   of the application (RQL server, web server) the script applies.
       
    33   Its value could be :
       
    34 
       
    35   * `common`, applies to the RQL server as well as the web server and updates
       
    36     files on the hard drive (configuration files migration for example).
       
    37 
       
    38   * `web`, applies only to the web server and updates files on the hard drive.
       
    39 
       
    40   * `repository`, applies only to the RQL server and updates files on the
       
    41     hard drive.
       
    42 
       
    43   * `Any`, applies only to the RQL server and updates data in the database
       
    44     (schema and data migration for example).
       
    45 
       
    46 Again in the directory `migration`, the file `depends.map` allows to indicate
       
    47 that for the migration to a particular model version, you always have to first
       
    48 migrate to a particular *CubicWeb* version. This file can contain comments (lines
       
    49 starting with `#`) and a dependency is listed as follows: ::
       
    50 
       
    51   <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
       
    52 
       
    53 For example: ::
       
    54 
       
    55   0.12.0: 2.26.0
       
    56   0.13.0: 2.27.0
       
    57   # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
       
    58   0.15.0: 2.28.0
       
    59 
       
    60 Base context
       
    61 ------------
       
    62 
       
    63 The following identifiers are pre-defined in migration scripts:
       
    64 
       
    65 * `config`, instance configuration
       
    66 
       
    67 * `interactive_mode`, boolean indicating that the script is executed in
       
    68   an interactive mode or not
       
    69 
       
    70 * `versions_map`, dictionary of migrated versions  (key are cubes
       
    71   names, including 'cubicweb', values are (from version, to version)
       
    72 
       
    73 * `confirm(question)`, function asking the user and returning true
       
    74   if the user answers yes, false otherwise (always returns true in
       
    75   non-interactive mode)
       
    76 
       
    77 * `_()` is equivalent to `unicode` allowing to flag the strings to
       
    78   internationalize in the migration scripts.
       
    79 
       
    80 In the `repository` scripts, the following identifiers are also defined:
       
    81 
       
    82 * `commit(ask_confirm=True)`, request confirming and executing a "commit"
       
    83 
       
    84 * `schema`, instance schema (readen from the database)
       
    85 
       
    86 * `fsschema`, installed schema on the file system (e.g. schema of
       
    87   the updated model and cubicweb)
       
    88 
       
    89 * `repo`, repository object
       
    90 
       
    91 * `session`, repository session object
       
    92 
       
    93 
       
    94 New cube dependencies
       
    95 ---------------------
       
    96 
       
    97 If your code depends on some new cubes, you have to add them in a migration
       
    98 script by using:
       
    99 
       
   100 * `add_cube(cube, update_database=True)`, add a cube.
       
   101 * `add_cubes(cubes, update_database=True)`, add a list of cubes.
       
   102 
       
   103 The `update_database` parameter is telling if the database schema
       
   104 should be updated or if only the relevant persistent property should be
       
   105 inserted (for the case where a new cube has been extracted from an
       
   106 existing one, so the new cube schema is actually already in there).
       
   107 
       
   108 If some of the added cubes are already used by an instance, they'll simply be
       
   109 silently skipped.
       
   110 
       
   111 
       
   112 Schema migration
       
   113 ----------------
       
   114 The following functions for schema migration are available in `repository`
       
   115 scripts:
       
   116 
       
   117 * `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
       
   118   attribute to an existing entity type. If the attribute type is not specified,
       
   119   then it is extracted from the updated schema.
       
   120 
       
   121 * `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
       
   122   existing entity type.
       
   123 
       
   124 * `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
       
   125 
       
   126 * `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
       
   127   If `auto` is True, all the relations using this entity type and having a known
       
   128   entity type on the other hand will automatically be added.
       
   129 
       
   130 * `drop_entity_type(etype, commit=True)`, removes an entity type and all the
       
   131   relations using it.
       
   132 
       
   133 * `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
       
   134 
       
   135 * `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
       
   136   type. If `addrdef` is True, all the relations definitions of this type will
       
   137   be added.
       
   138 
       
   139 * `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
       
   140   definitions of this type.
       
   141 
       
   142 * `rename_relation_type(oldname, newname, commit=True)`, renames a relation type.
       
   143 
       
   144 * `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
       
   145   relation definition.
       
   146 
       
   147 * `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
       
   148   a relation definition.
       
   149 
       
   150 * `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
       
   151   synchronizes properties and/or permissions on:
       
   152   - the whole schema if ertype is None
       
   153   - an entity or relation type schema if ertype is a string
       
   154   - a relation definition  if ertype is a 3-uple (subject, relation, object)
       
   155 
       
   156 * `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
       
   157   properties of a relation definition by using the named parameters of the properties
       
   158   to change.
       
   159 
       
   160 * `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
       
   161   relation <rtype> of entity type <etype>.
       
   162 
       
   163 * `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
       
   164   for the relation <rtype> of entity type <etype>.
       
   165 
       
   166 Data migration
       
   167 --------------
       
   168 The following functions for data migration are available in `repository` scripts:
       
   169 
       
   170 * `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
       
   171   query, either to interrogate or update. A result set object is returned.
       
   172 
       
   173 * `add_entity(etype, *args, **kwargs)`, adds a new entity of the given type.
       
   174   The attribute and relation values are specified as named positional
       
   175   arguments.
       
   176 
       
   177 Workflow creation
       
   178 -----------------
       
   179 
       
   180 The following functions for workflow creation are available in `repository`
       
   181 scripts:
       
   182 
       
   183 * `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
       
   184   for a given type(s)
       
   185 
       
   186 You can find more details about workflows in the chapter :ref:`Workflow` .
       
   187 
       
   188 Configuration migration
       
   189 -----------------------
       
   190 
       
   191 The following functions for configuration migration are available in all
       
   192 scripts:
       
   193 
       
   194 * `option_renamed(oldname, newname)`, indicates that an option has been renamed
       
   195 
       
   196 * `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
       
   197   belong anymore to the same group.
       
   198 
       
   199 * `option_added(oldname, newname)`, indicates that an option has been added.
       
   200 
       
   201 * `option_removed(oldname, newname)`, indicates that an option has been deleted.
       
   202 
       
   203 The `config` variable is an object which can be used to access the
       
   204 configuration values, for reading and updating, with a dictionary-like
       
   205 syntax. 
       
   206 
       
   207 Example 1: migration script changing the variable 'sender-addr' in
       
   208 all-in-one.conf. The script also checks that in that the instance is
       
   209 configured with a known value for that variable, and only updates the
       
   210 value in that case.
       
   211 
       
   212 .. sourcecode:: python
       
   213 
       
   214  wrong_addr = 'cubicweb@loiglab.fr' # known wrong address
       
   215  fixed_addr = 'cubicweb@logilab.fr'
       
   216  configured_addr = config.get('sender-addr')
       
   217  # check that the address has not been hand fixed by a sysadmin
       
   218  if configured_addr == wrong_addr: 
       
   219      config['sender-addr'] = fixed-addr
       
   220      config.save()
       
   221 
       
   222 Example 2: checking the value of the database backend driver, which
       
   223 can be useful in case you need to issue backend-dependent raw SQL
       
   224 queries in a migration script.
       
   225 
       
   226 .. sourcecode:: python
       
   227 
       
   228  dbdriver  = config.sources()['system']['db-driver']
       
   229  if dbdriver == "sqlserver2005":
       
   230      # this is now correctly handled by CW :-)
       
   231      sql('ALTER TABLE cw_Xxxx ALTER COLUMN cw_name varchar(64) NOT NULL;')
       
   232      commit()
       
   233  else: # postgresql
       
   234      sync_schema_props_perms(ertype=('Xxxx', 'name', 'String'),
       
   235      syncperms=False)
       
   236 
       
   237 
       
   238 Others migration functions
       
   239 --------------------------
       
   240 Those functions are only used for low level operations that could not be
       
   241 accomplished otherwise or to repair damaged databases during interactive
       
   242 session. They are available in `repository` scripts:
       
   243 
       
   244 * `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
       
   245 * `add_entity_type_table(etype, commit=True)`
       
   246 * `add_relation_type_table(rtype, commit=True)`
       
   247 * `uninline_relation(rtype, commit=True)`
       
   248 
       
   249 
       
   250 [FIXME] Add explanation on how to use cubicweb-ctl shell