Customize Migration Packets
General
Information
- Migration packets are written in Python and are retrieved from the server. As a result, you have full access to the functions of the Python API.
- Before changes are applied, packets should always check whether the condition of the system meets the expectations.
This is meant to guarantee that customer specific customizing is not overwritten by packets. - In order to be correctly recognized as migration packets, packets must inherit from the
BasePacket
basic class. - For some frequently occurring cases, there are specialized basic classes that come with helpful methods.
- All of the classes listed here can be imported by
ppms.migration
. - A packet communicates its status to the framework via the
success()
,fail()
, andskip()
methods.- These methods set an internal flag. After they have been opened, no other packet code must be executed.
- Several packets can easily be defined in a module.
- The migration packets included in the delivery of PLANTA are mentioned in the Releases and Downloads topic of the respective release.
- The status of the migration packets can be checked in the respective module of the Migration Packets panel.
Details
- The migration packet is executed in the following sequence:
- 1. Server version
- 2. Category (e.g. "Mandatory packet")
- 3. File name
Note
- The
start_migration.py
(under /py/planta_de/ppms and /py/system/ppms) files must not be changed.
Template
# -*- coding: utf-8 -*-
from ppms import ppms
from ppms.migration.packet import *
class ExamplePacket(BasePacket):
'''Short 80 character line summarizing what this packet does
A longer description that goes into more detail and explains
what corner cases one could run into
'''
wi_number = None # The workitem number this packet belongs to. Only relevant for packets by PLANTA
version = 1
done_after_success = True # Sets the "Erledigt" flag after running successfully
run_on_startup = True # Runs this migration packet when the server is started in migration mode
category = PacketCategory.CATEGORY_MANDATORY # Categorizes the packet
def fix(self, runner):
# do something useful
if errors:
return self.fail('Encountered errors')
return self.success()
Note
done_after_success
= False is recommended for (auxiliary) packets that check the customizing, so that they are further on displayed in the Packets to be executed area after execution.
Special Functions
Information
- The
StopMigrationProcessException
class can be imported fromppms.migration
. If this exception is raised by a packet, no further packets are executed afterwards. - The
ppms.migration
package also comes with two decorators for simply skipping packets:skipIf
andskipUnless
@skipIf(dbms_name == 'Oracle', 'Not necessary on a Oracle db')
def fix(self, packet_runner):
...
@skipUnless(dbms_name == 'Oracle', 'Only necessary with a Oracle db')
def fix(self, packet_runner):
...
- Packets write their logfiles as a simple text by default. This structure can be adjusted system-wide if necessary. For this purpose you have to change two properties in the packet class:
property | Default values |
---|---|
logging_prefix | Returns a time stamp by default, which is written before every log entry |
logfile_suffix | Sets the extension of the logfile to .log by default |
Best Practice
Information
- If a packet has multiple interim stages which can be repeated regardless of whether they have been completed successfully or have failed, it is recommended to collect the errors and open
success()
orfail()
at the end of thefix()
method, according to the number of errors. - If a packet carries out DML statements which cannot be undone by a simple rollback, the
rollback()
method of the packet should be implemented in order to be able to undo the changes if necessary.
Execute Packets (Framework)
Information
- Migration packets are executed by the server via a framework.
- This framework defines which packets are executed, executes them, and saves the logfile in the database if necessary.
- The instance of the framework which carries out the packet is handed over to the
fix()
method. - The basic class of the framework is the
AbstractPacketRunner
underppms.migration.framework
.
Specialized framework classes included in the PLANTA delivery
Class | Use |
---|---|
StartupRunner | Reads all packets from the file system and carries all out with Upon system start = and Completed = |
DefaultRunner | Carries out all packets with Completed = |
SinglePacketRunner | Carries out an individual packet |
RegtestRunner | Carries out an arbitrary number of packets but does not write entries in the history table |
RegtestRunnerWithHistory | Modified version of the RegtestRunner , which also makes entries in the history table |
Overview of the Different Basic Classes
BasePacket
Information
- All migration packets inherit from this class.
- It can serve as a base for any type of migration step.
Class attributes
Attribute | Expected type | Function |
---|---|---|
version | Integer | Specifies the version of the packet |
done_after_success | Boolean | Sets the checkmark in the Completed field if the migration packet has expired |
run_on_startup | Boolean | Carries out the packet if the server is started in migration mode |
Abstract methods
Methods | Function | Must be implemented |
---|---|---|
fix(self, packet_runner) | fix() is called by the migration framework. This method contains the actual logic of the packet | Yes |
update(self, packet_runner, previous_packet_uuid) | The update() method is opened when a packet has already been run with an inferior version version | No |
rollback(self) | This method is opened by the framework after the fix() or update() method if the packet has failed | No |
Useful methods
Methods | Function |
---|---|
log(self, text) | Writes a handed over text in the logfile of the packet.
PY
|
log_heading(self, text, level=0) | Schreibt eine Überschrift in das Logfile. level muss ein integer zwischen 0 und 4 sein. The higher, the "smaller" the heading |
SQLPacket
Information
- The SQLPacket Basic Class offers several attributes and methods for running SQL statements
Class attributes
Attribute | Value |
---|---|
sql_planta_de_dbms | Path to the sql/planta_de/<dbms> directory Whereas <dbms> is replaced by the respective database system (oracle/mssql) |
sql_planta_ch_dbms | Path to the sql/planta_ch/<dbms> directory Whereas <dbms> is replaced by the respective database system (oracle/mssql) |
sql_customer_dbms | Path to the sql/customer/<dbms> directory Whereas <dbms> is replaced by the respective database system (oracle/mssql) |
sql_planta_de_ansi | Path to the sql/planta_de/<ansi> directory |
sql_planta_ch_ansi | Path to the sql/planta_ch/<ansi> directory |
sql_customer_ansi | Path to the sql/customer/<ansi> directory |
Methods
Methods | Function |
---|---|
get_queries_from_file(self, fpath) | Reads the file at the specified path, splits the content at the semicolon and returns the result to the list. |
modify_and_log(self, query) | Carries out the handed over statement with db_modify and returns the number of lines. As a result, the statement as well as the number of changed lines are written into the logfile. |
DeprecatedPythonPacket
Information
- The DeprecatedPythonPacket class is useful if you want to find an obsolete Python code in the system.
- The
fix()
method is not implemented for this class!
Abstract methods
Methods | Function |
---|---|
get_matching_objects(self, iterable_to_filter) | This method receives a list of instances. These instances have a source attribute which contains the source text of the object. The method must return a list of these instances that contain the obsolete Python code |
introduction(self) | The introduction method is opened before the code is searched and can be used to write a short text in the logfile |
Properties
property | Function |
---|---|
custom_server_folder_blacklist | A tuple of folder names that are to be omitted in the search |
custom_server_file_blacklist | A tuple of folder names that are to be omitted in the search |
MigratePythonPacket
Information
- A class for migrating fields with a Python code to a newer date.
- Instead of the customizer, the class checks whether the system has a particular condition and whether the changes have been made correctly.
- To use this function, an md5-Hash of the initial condition as well as of the target condition must be generated.
Attributes
The following attributes are constants that are passed on as parameters to the migrate_python
method.
Attribute | Field that is to be changed |
---|---|
CU_TYPE_DATAITEM | Value range |
CU_TYPE_IRONPYTHON | IronPython Script |
CU_TYPE_DF_CONFIG | Data field configuration |
CU_TYPE_MODULE | Macro |
CU_TYPE_PROCESS_RULE | Rule |
CU_TYPE_GLOBAL_SETTING | Template code |
Methods
Methods | Function |
---|---|
migrate_python(self, before_hash, after_hash, cu_type, keys, fix_func) | Checks whether the system condition is as expected, makes changes to the system, and checks whether the target condition meets the expectations. before_hash Md5 hash that is expected in the system after_hash : Md5 hash that is expected in the system after the change has been made cu_type : One of the constants listed above keys : See below fix_func : A function that takes source code as an argument and returns it corrected. |
Values for the keys
parameter
cu_type | Expected data type | Expected value |
---|---|---|
CU_TYPE_DATAITEM | string | DI |
CU_TYPE_IRONPYTHON | List | DA as string, DF as integer |
CU_TYPE_DF_CONFIG | List | DA as string, DF as integer |
CU_TYPE_MODULE | string | MOD |
CU_TYPE_PROCESS_RULE | string | Process rules |
CU_TYPE_GLOBAL_SETTING | string | UUID |
ChangeDTPPacket
Information
- Class with methods for changing arbitrary attributes of DTP records.
Methods
Methods | Function |
---|---|
get_record(self, dt_num, key_list, di_list) | A wrapper for the ppms.search_record method that has been extended by logging. Either returns DTPRecord or None |
verify_value(self, record, attribute, value) | Function for checking the value of arbitrary attributes of a record. The attribute parameter is the DI Python ID of the field to be checked. Returns True or False . |
change_value(self, record, attribute, old_value, new_value) | Checks the system condition, makes the change, and checks whether the change has been saved correctly. The attribute parameter is the DI Python ID of the field to be changed. Returns True or False . |