Implement configuration management for DB2
In this feature we implement configuration management for DB2 database manager through Trove. Change-Id: I303b8ddeafe7c67ec80dc8ec9e8489af913e23f7 Implements: blueprint db2-config-group
This commit is contained in:
parent
4d1bea7429
commit
0609f85d74
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Add support for configuration group management
|
||||
for DB2 Express-C.
|
@ -84,3 +84,14 @@ class VerticaConfParser(object):
|
||||
|
||||
def parse(self):
|
||||
return self.CODEC.deserialize(self.config).items()
|
||||
|
||||
|
||||
class DB2ConfParser(object):
|
||||
|
||||
CODEC = stream_codecs.PropertiesCodec(delimiter='=')
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def parse(self):
|
||||
return self.CODEC.deserialize(self.config).items()
|
||||
|
@ -39,6 +39,7 @@ SERVICE_PARSERS = {
|
||||
'cassandra': configurations.CassandraConfParser,
|
||||
'redis': configurations.RedisConfParser,
|
||||
'vertica': configurations.VerticaConfParser,
|
||||
'db2': configurations.DB2ConfParser,
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from trove.common.i18n import _
|
||||
@ -42,6 +44,10 @@ class Manager(manager.Manager):
|
||||
def status(self):
|
||||
return self.appStatus
|
||||
|
||||
@property
|
||||
def configuration_manager(self):
|
||||
return self.app.configuration_manager
|
||||
|
||||
def do_prepare(self, context, packages, databases, memory_mb, users,
|
||||
device_path, mount_point, backup_info,
|
||||
config_contents, root_password, overrides,
|
||||
@ -51,13 +57,18 @@ class Manager(manager.Manager):
|
||||
device = volume.VolumeDevice(device_path)
|
||||
device.unmount_device(device_path)
|
||||
device.format()
|
||||
device.mount(mount_point)
|
||||
LOG.debug('Mounted the volume.')
|
||||
if os.path.exists(mount_point):
|
||||
device.migrate_data(mount_point)
|
||||
device.mount(mount_point)
|
||||
LOG.debug("Mounted the volume.")
|
||||
self.app.update_hostname()
|
||||
self.app.change_ownership(mount_point)
|
||||
self.app.start_db()
|
||||
if backup_info:
|
||||
self._perform_restore(backup_info, context, mount_point)
|
||||
if config_contents:
|
||||
self.app.configuration_manager.save_configuration(
|
||||
config_contents)
|
||||
|
||||
def restart(self, context):
|
||||
"""
|
||||
@ -133,3 +144,15 @@ class Manager(manager.Manager):
|
||||
def create_backup(self, context, backup_info):
|
||||
LOG.debug("Creating backup.")
|
||||
backup.backup(context, backup_info)
|
||||
|
||||
def update_overrides(self, context, overrides, remove=False):
|
||||
LOG.debug("Updating overrides.")
|
||||
if remove:
|
||||
self.app.remove_overrides()
|
||||
else:
|
||||
self.app.update_overrides(context, overrides)
|
||||
|
||||
def apply_overrides(self, context, overrides):
|
||||
if overrides:
|
||||
LOG.debug("Applying overrides: " + str(overrides))
|
||||
self.app.apply_overrides(overrides)
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import encodeutils
|
||||
|
||||
@ -20,7 +22,11 @@ from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common import instance as rd_instance
|
||||
from trove.common.stream_codecs import PropertiesCodec
|
||||
from trove.common import utils as utils
|
||||
from trove.guestagent.common.configuration import ConfigurationManager
|
||||
from trove.guestagent.common.configuration import ImportOverrideStrategy
|
||||
from trove.guestagent.common import guestagent_utils
|
||||
from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.datastore.experimental.db2 import system
|
||||
from trove.guestagent.datastore import service
|
||||
@ -28,6 +34,9 @@ from trove.guestagent.db import models
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
MOUNT_POINT = CONF.db2.mount_point
|
||||
FAKE_CFG = os.path.join(MOUNT_POINT, "db2.cfg.fake")
|
||||
DB2_DEFAULT_CFG = os.path.join(MOUNT_POINT, "db2_default_dbm.cfg")
|
||||
|
||||
|
||||
class DB2App(object):
|
||||
@ -43,6 +52,87 @@ class DB2App(object):
|
||||
)
|
||||
LOG.debug("state_change_wait_time = %s." % self.state_change_wait_time)
|
||||
self.status = status
|
||||
self.dbm_default_config = {}
|
||||
self.init_config()
|
||||
|
||||
def init_config(self):
|
||||
if not operating_system.exists(MOUNT_POINT, True):
|
||||
operating_system.create_directory(MOUNT_POINT,
|
||||
system.DB2_INSTANCE_OWNER,
|
||||
system.DB2_INSTANCE_OWNER,
|
||||
as_root=True)
|
||||
"""
|
||||
The database manager configuration file - db2systm is stored under the
|
||||
/home/db2inst1/sqllib directory. To update the configuration
|
||||
parameters, DB2 recommends using the command - UPDATE DBM CONFIGURATION
|
||||
commands instead of directly updating the config file.
|
||||
|
||||
The existing PropertiesCodec implementation has been reused to handle
|
||||
text-file operations. Configuration overrides are implemented using
|
||||
the ImportOverrideStrategy of the guestagent configuration manager.
|
||||
"""
|
||||
LOG.debug("Initialize DB2 configuration")
|
||||
revision_dir = (
|
||||
guestagent_utils.build_file_path(
|
||||
os.path.join(MOUNT_POINT,
|
||||
os.path.dirname(system.DB2_INSTANCE_OWNER)),
|
||||
ConfigurationManager.DEFAULT_STRATEGY_OVERRIDES_SUB_DIR)
|
||||
)
|
||||
if not operating_system.exists(FAKE_CFG):
|
||||
operating_system.write_file(FAKE_CFG, '', as_root=True)
|
||||
operating_system.chown(FAKE_CFG, system.DB2_INSTANCE_OWNER,
|
||||
system.DB2_INSTANCE_OWNER, as_root=True)
|
||||
self.configuration_manager = (
|
||||
ConfigurationManager(FAKE_CFG, system.DB2_INSTANCE_OWNER,
|
||||
system.DB2_INSTANCE_OWNER,
|
||||
PropertiesCodec(delimiter='='),
|
||||
requires_root=True,
|
||||
override_strategy=ImportOverrideStrategy(
|
||||
revision_dir, "cnf"))
|
||||
)
|
||||
'''
|
||||
Below we are getting the database manager default configuration and
|
||||
saving it to the DB2_DEFAULT_CFG file. This is done to help with
|
||||
correctly resetting the configurations to the original values when
|
||||
user wants to detach a user-defined configuration group from an
|
||||
instance. DB2 provides a command to reset the database manager
|
||||
configuration parameters (RESET DBM CONFIGURATION) but this command
|
||||
resets all the configuration parameters to the system defaults. When
|
||||
we build a DB2 guest image there are certain configurations
|
||||
parameters like SVCENAME which we set so that the instance can start
|
||||
correctly. Hence resetting this value to the system default will
|
||||
render the instance in an unstable state. Instead, the recommended
|
||||
way for resetting a subset of configuration parameters is to save
|
||||
the output of GET DBM CONFIGURATION of the original configuration
|
||||
and then call UPDATE DBM CONFIGURATION to reset the value.
|
||||
http://www.ibm.com/support/knowledgecenter/SSEPGG_10.5.0/
|
||||
com.ibm.db2.luw.admin.cmd.doc/doc/r0001970.html
|
||||
'''
|
||||
if not operating_system.exists(DB2_DEFAULT_CFG):
|
||||
run_command(system.GET_DBM_CONFIGURATION % {
|
||||
"dbm_config": DB2_DEFAULT_CFG})
|
||||
self.process_default_dbm_config()
|
||||
|
||||
def process_default_dbm_config(self):
|
||||
"""
|
||||
Once the default database manager configuration is saved to
|
||||
DB2_DEFAULT_CFG, we try to store the configuration parameters
|
||||
and values into a dictionary object, dbm_default_config. For
|
||||
example, a sample content of the database manager configuration
|
||||
file looks like this:
|
||||
Buffer pool (DFT_MON_BUFPOOL) = OFF
|
||||
We need to process this so that we key it on the configuration
|
||||
parameter DFT_MON_BUFPOOL.
|
||||
"""
|
||||
with open(DB2_DEFAULT_CFG) as cfg_file:
|
||||
for line in cfg_file:
|
||||
if '=' in line:
|
||||
item = line.rstrip('\n').split(' = ')
|
||||
fIndex = item[0].rfind('(')
|
||||
lIndex = item[0].rfind(')')
|
||||
if fIndex > -1:
|
||||
param = item[0][fIndex + 1: lIndex]
|
||||
self.dbm_default_config.update({param: item[1]})
|
||||
|
||||
def update_hostname(self):
|
||||
"""
|
||||
@ -92,14 +182,8 @@ class DB2App(object):
|
||||
"Command to disable DB2 server on boot failed."))
|
||||
|
||||
def start_db_with_conf_changes(self, config_contents):
|
||||
'''
|
||||
Will not be implementing configuration change API for DB2 in
|
||||
the Kilo release. Currently all that this method does is to start
|
||||
the DB2 server without any configuration changes. Looks like
|
||||
this needs to be implemented to enable volume resize on the guest
|
||||
agent side.
|
||||
'''
|
||||
LOG.info(_("Starting DB2 with configuration changes."))
|
||||
self.configuration_manager.save_configuration(config_contents)
|
||||
self.start_db(True)
|
||||
|
||||
def start_db(self, update_db=False):
|
||||
@ -142,6 +226,50 @@ class DB2App(object):
|
||||
finally:
|
||||
self.status.end_restart()
|
||||
|
||||
def update_overrides(self, context, overrides, remove=False):
|
||||
if overrides:
|
||||
self.apply_overrides(overrides)
|
||||
|
||||
def remove_overrides(self):
|
||||
config = self.configuration_manager.get_user_override()
|
||||
self._reset_config(config)
|
||||
self.configuration_manager.remove_user_override()
|
||||
|
||||
def apply_overrides(self, overrides):
|
||||
self._apply_config(overrides)
|
||||
self.configuration_manager.apply_user_override(overrides)
|
||||
|
||||
def _update_dbm_config(self, param, value):
|
||||
out, err = run_command(
|
||||
system.UPDATE_DBM_CONFIGURATION % {
|
||||
"parameter": param,
|
||||
"value": value})
|
||||
if err:
|
||||
if err.is_warning():
|
||||
LOG.warning(err)
|
||||
else:
|
||||
LOG.error(err)
|
||||
raise RuntimeError(_("Failed to update config %s") % param)
|
||||
|
||||
def _reset_config(self, config):
|
||||
try:
|
||||
for k, v in config.iteritems():
|
||||
default_cfg_value = self.dbm_default_config[k]
|
||||
self._update_dbm_config(k, default_cfg_value)
|
||||
except Exception:
|
||||
LOG.exception(_("DB2 configuration reset failed."))
|
||||
raise RuntimeError(_("DB2 configuration reset failed."))
|
||||
LOG.info(_("DB2 configuration reset completed."))
|
||||
|
||||
def _apply_config(self, config):
|
||||
try:
|
||||
for k, v in config.items():
|
||||
self._update_dbm_config(k, v)
|
||||
except Exception:
|
||||
LOG.exception(_("DB2 configuration apply failed"))
|
||||
raise RuntimeError(_("DB2 configuration apply failed"))
|
||||
LOG.info(_("DB2 config apply completed."))
|
||||
|
||||
|
||||
class DB2AppStatus(service.BaseDbStatus):
|
||||
"""
|
||||
|
@ -58,3 +58,6 @@ GET_DB_SIZE = (
|
||||
"db2 call get_dbsize_info(?, ?, ?, -1) ")
|
||||
GET_DB_NAMES = ("find /home/db2inst1/db2inst1/backup/ -type f -name '*.001' |"
|
||||
" grep -Po \"(?<=backup/)[^.']*(?=\.)\"")
|
||||
GET_DBM_CONFIGURATION = "db2 get dbm configuration > %(dbm_config)s"
|
||||
UPDATE_DBM_CONFIGURATION = ("db2 update database manager configuration using "
|
||||
"%(parameter)s %(value)s")
|
||||
|
454
trove/templates/db2/validation-rules.json
Normal file
454
trove/templates/db2/validation-rules.json
Normal file
@ -0,0 +1,454 @@
|
||||
{
|
||||
"configuration-parameters": [
|
||||
{
|
||||
"description": "Agent stack size",
|
||||
"type": "integer",
|
||||
"name": "AGENT_STACK_SZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Alternate encryption algorithm for incoming connections at server",
|
||||
"type": "integer",
|
||||
"name": "ALTERNATE_AUTH_ENC",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Max number of concurrently active databases",
|
||||
"type": "integer",
|
||||
"name": "NUMDB",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Federated Database Support",
|
||||
"type": "integer",
|
||||
"name": "FEDERATED",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Transaction processor monitor name",
|
||||
"type": "string",
|
||||
"name": "TP_MON_NAME",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Default charge-back account",
|
||||
"type": "string",
|
||||
"name": "DFT_ACCOUNT_STR",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Size of rotating db2diag & notify logs (MB)",
|
||||
"type": "integer",
|
||||
"name": "DIAGSIZE",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Buffer pool",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_BUFPOOL",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Lock",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_LOCK",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Sort",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_SORT",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Statement",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_STMT",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Table",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_TABLE",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Timestamp",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_TIMESTAMP",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Default database monitor switch for Unit of work",
|
||||
"type": "integer",
|
||||
"name": "DFT_MON_UOW",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Monitor health of instance and databases",
|
||||
"type": "integer",
|
||||
"name": "HEALTH_MON",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "SYSADM group name",
|
||||
"type": "string",
|
||||
"name": "SYSADM_GROUP",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SYSCTRL group name",
|
||||
"type": "string",
|
||||
"name": "SYSCTRL_GROUP",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SYSMAINT group name",
|
||||
"type": "string",
|
||||
"name": "SYSMAINT_GROUP",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SYSMON group name",
|
||||
"type": "string",
|
||||
"name": "SYSMAINT_GROUP",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Client Userid-Password Plugin",
|
||||
"type": "string",
|
||||
"name": "CLNT_PW_PLUGIN",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Client Kerberos Plugin",
|
||||
"type": "string",
|
||||
"name": "CLNT_KRB_PLUGIN",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Group Plugin",
|
||||
"type": "string",
|
||||
"name": "GROUP_PLUGIN",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "GSS Plugin for Local Authorization",
|
||||
"type": "string",
|
||||
"name": "LOCAL_GSSPLUGIN",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Server Plugin Mode",
|
||||
"type": "integer",
|
||||
"name": "SRV_PLUGIN_MODE",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Server List of GSS Plugins",
|
||||
"type": "string",
|
||||
"name": "SRVCON_GSSPLUGIN_LIST",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Server Userid-Password Plugin",
|
||||
"type": "string",
|
||||
"name": "SRVCON_PW_PLUGIN",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Server Connection Authentication",
|
||||
"type": "string",
|
||||
"name": "SRVCON_AUTH",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Database manager authentication",
|
||||
"type": "integer",
|
||||
"name": "AUTHENTICATION",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Alternate authentication",
|
||||
"type": "integer",
|
||||
"name": "ALTERNATE_AUTH_ENC",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Cataloging allowed without authority",
|
||||
"type": "integer",
|
||||
"name": "CATALOG_NOAUTH",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Trust all clients",
|
||||
"type": "integer",
|
||||
"name": "TRUST_ALLCLNTS",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Trusted client authentication",
|
||||
"type": "integer",
|
||||
"name": "TRUST_CLNTAUTH",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Bypass federated authentication",
|
||||
"type": "integer",
|
||||
"name": "FED_NOAUTH",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Database monitor heap size(4KB)",
|
||||
"type": "integer",
|
||||
"name": "MON_HEAP_SZ",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Java Virtual Machine heap size(4KB)",
|
||||
"type": "integer",
|
||||
"name": "JAVA_HEAP_SZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Audit buffer size(4KB)",
|
||||
"type": "integer",
|
||||
"name": "AUDIT_BUF_SZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Agent stack size",
|
||||
"type": "integer",
|
||||
"name": "AGENT_STACK_SZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Sort heap threshold (4KB)",
|
||||
"type": "integer",
|
||||
"name": "SHEAPTHRES",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Directory cache support",
|
||||
"type": "integer",
|
||||
"name": "DIR_CACHE",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Application support layer heap size (4KB)",
|
||||
"type": "integer",
|
||||
"name": "ASLHEAPSZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Max requester I/O block size (bytes)",
|
||||
"type": "integer",
|
||||
"name": "RQRIOBLK",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Workload impact by throttled utilities",
|
||||
"type": "integer",
|
||||
"name": "UTIL_IMPACT_LIM",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Priority of agents",
|
||||
"type": "integer",
|
||||
"name": "AGENTPRI",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Agent pool size",
|
||||
"type": "integer",
|
||||
"name": "NUM_POOLAGENTS",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Initial number of agents in pool",
|
||||
"type": "integer",
|
||||
"name": "NUM_INITAGENTS",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Max number of coordinating agents",
|
||||
"type": "integer",
|
||||
"name": "MAX_COORDAGENTS",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Max number of client connections",
|
||||
"type": "integer",
|
||||
"name": "MAX_CONNECTIONS",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Keep fenced process",
|
||||
"type": "integer",
|
||||
"name": "KEEPFENCED",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Number of pooled fenced processes",
|
||||
"type": "integer",
|
||||
"name": "FENCED_POOL",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Initial number of fenced processes",
|
||||
"type": "integer",
|
||||
"name": "NUM_INITFENCED",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Index re-creation time and redo index build",
|
||||
"type": "integer",
|
||||
"name": "INDEXREC",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Transaction manager database name",
|
||||
"type": "string",
|
||||
"name": "TM_DATABASE",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Transaction resync interval (sec)",
|
||||
"type": "integer",
|
||||
"name": "RESYNC_INTERVAL",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SPM name",
|
||||
"type": "string",
|
||||
"name": "SPM_NAME",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SPM log size",
|
||||
"type": "integer",
|
||||
"name": "SPM_LOG_FILE_SZ",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SPM resync agent limit",
|
||||
"type": "integer",
|
||||
"name": "SPM_MAX_RESYNC",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Discovery mode",
|
||||
"type": "integer",
|
||||
"name": "DISCOVER",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Discover server instance",
|
||||
"type": "integer",
|
||||
"name": "DISCOVER_INST",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "SSL server keydb file",
|
||||
"type": "string",
|
||||
"name": "SSL_SVR_KEYDB",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL server stash file",
|
||||
"type": "string",
|
||||
"name": "SSL_SVR_STASH",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL server certificate label",
|
||||
"type": "string",
|
||||
"name": "SSL_SVR_LABEL",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL cipher specs",
|
||||
"type": "string",
|
||||
"name": "SSL_CIPHERSPECS",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL versions",
|
||||
"type": "string",
|
||||
"name": "SSL_VERSIONS",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL client keydb file",
|
||||
"type": "string",
|
||||
"name": "SSL_CLNT_KEYDB",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "SSL client stash file",
|
||||
"type": "string",
|
||||
"name": "SSL_CLNT_STASH",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "Maximum query degree of parallelism",
|
||||
"type": "integer",
|
||||
"name": "MAX_QUERYDEGREE",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Enable intra-partition parallelism",
|
||||
"type": "integer",
|
||||
"name": "INTRA_PARALLEL",
|
||||
"restart_required": true
|
||||
},
|
||||
{
|
||||
"description": "No. of int. communication buffers(4KB)",
|
||||
"type": "integer",
|
||||
"name": "FCM_NUM_BUFFERS",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "No. of int. communication channels",
|
||||
"type": "integer",
|
||||
"name": "FCM_NUM_CHANNELS",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "db2start/db2stop timeout (min)",
|
||||
"type": "integer",
|
||||
"name": "START_STOP_TIME",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "WLM dispatcher enabled",
|
||||
"type": "integer",
|
||||
"name": "WLM_DISPATCHER",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "WLM dispatcher concurrency",
|
||||
"type": "integer",
|
||||
"name": "WLM_DISP_CONCUR",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "WLM dispatcher CPU shares enabled",
|
||||
"type": "integer",
|
||||
"name": "WLM_DISP_CPU_SHARES",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "WLM dispatcher min. utilization (%)",
|
||||
"type": "integer",
|
||||
"name": "WLM_DISP_MIN_UTIL",
|
||||
"restart_required": false
|
||||
},
|
||||
{
|
||||
"description": "Communication buffer exit library list",
|
||||
"type": "string",
|
||||
"name": "COMM_EXIT_LIST",
|
||||
"restart_required": false
|
||||
}
|
||||
]
|
||||
}
|
@ -210,7 +210,7 @@ register(["user"], user_actions_groups)
|
||||
# Register: Datastore based groups
|
||||
# These should contain all functionality currently supported by the datastore
|
||||
register(["db2_supported"], common_groups,
|
||||
database_actions_groups, user_actions_groups)
|
||||
database_actions_groups, user_actions_groups, configuration_groups)
|
||||
register(["cassandra_supported"], common_groups,
|
||||
user_actions_groups, database_actions_groups,
|
||||
backup_groups, configuration_groups, cluster_actions_groups)
|
||||
|
44
trove/tests/scenario/helpers/db2_helper.py
Normal file
44
trove/tests/scenario/helpers/db2_helper.py
Normal file
@ -0,0 +1,44 @@
|
||||
# Copyright 2016 IBM Corporation
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from trove.tests.scenario.helpers.test_helper import TestHelper
|
||||
|
||||
|
||||
class Db2Helper(TestHelper):
|
||||
|
||||
def __init__(self, expected_override_name, report):
|
||||
super(Db2Helper, self).__init__(expected_override_name, report)
|
||||
|
||||
def get_helper_credentials(self):
|
||||
return {'name': 'lite', 'password': 'litepass', 'database': 'lite'}
|
||||
|
||||
def get_valid_user_definitions(self):
|
||||
return [{'name': 'user1', 'password': 'password1', 'databases': []},
|
||||
{'name': 'user2', 'password': 'password1',
|
||||
'databases': [{'name': 'db1'}]},
|
||||
{'name': 'user3', 'password': 'password1',
|
||||
'databases': [{'name': 'db1'}, {'name': 'db2'}]}]
|
||||
|
||||
def get_dynamic_group(self):
|
||||
return {'MON_HEAP_SZ': 40}
|
||||
|
||||
def get_non_dynamic_group(self):
|
||||
return {'NUMDB': 30}
|
||||
|
||||
def get_invalid_groups(self):
|
||||
return [{'timezone': 997},
|
||||
{"max_worker_processes": 'string_value'},
|
||||
{"standard_conforming_strings": 'string_value'}]
|
@ -24,6 +24,8 @@ from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.datastore.experimental.cassandra import (
|
||||
service as cass_service
|
||||
)
|
||||
from trove.guestagent.datastore.experimental.db2 import (
|
||||
service as db2_service)
|
||||
from trove.guestagent.strategies.backup import base as backupBase
|
||||
from trove.guestagent.strategies.backup.experimental.postgresql_impl \
|
||||
import PgBaseBackupUtil
|
||||
@ -443,7 +445,12 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
|
||||
DECRYPT + PIPE + UNZIP + PIPE + REDISBACKUP_RESTORE)
|
||||
|
||||
@patch.object(utils, 'execute_with_timeout')
|
||||
def test_backup_encrypted_db2backup_command(self, *mock):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def test_backup_encrypted_db2backup_command(self, *mock, **kwargs):
|
||||
backupBase.BackupRunner.is_encrypted = True
|
||||
backupBase.BackupRunner.encrypt_key = CRYPTO_KEY
|
||||
RunnerClass = utils.import_class(BACKUP_DB2_CLS)
|
||||
@ -454,7 +461,12 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
|
||||
self.assertIn("gz.enc", bkp.manifest)
|
||||
|
||||
@patch.object(utils, 'execute_with_timeout')
|
||||
def test_backup_not_encrypted_db2backup_command(self, *mock):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def test_backup_not_encrypted_db2backup_command(self, *mock, **kwargs):
|
||||
backupBase.BackupRunner.is_encrypted = False
|
||||
backupBase.BackupRunner.encrypt_key = CRYPTO_KEY
|
||||
RunnerClass = utils.import_class(BACKUP_DB2_CLS)
|
||||
@ -463,7 +475,12 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
|
||||
self.assertEqual(DB2BACKUP_CMD + PIPE + ZIP, bkp.command)
|
||||
self.assertIn("gz", bkp.manifest)
|
||||
|
||||
def test_restore_decrypted_db2backup_command(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def test_restore_decrypted_db2backup_command(self, *args, **kwargs):
|
||||
restoreBase.RestoreRunner.is_zipped = True
|
||||
restoreBase.RestoreRunner.is_encrypted = False
|
||||
RunnerClass = utils.import_class(RESTORE_DB2_CLS)
|
||||
@ -471,7 +488,12 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
|
||||
location="filename", checksum="md5")
|
||||
self.assertEqual(restr.restore_cmd, UNZIP + PIPE + DB2BACKUP_RESTORE)
|
||||
|
||||
def test_restore_encrypted_db2backup_command(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def test_restore_encrypted_db2backup_command(self, *args, **kwargs):
|
||||
restoreBase.RestoreRunner.is_zipped = True
|
||||
restoreBase.RestoreRunner.is_encrypted = True
|
||||
restoreBase.RestoreRunner.encrypt_key = CRYPTO_KEY
|
||||
@ -946,7 +968,12 @@ class PostgresqlBackupTests(trove_testtools.TestCase):
|
||||
|
||||
class DB2BackupTests(trove_testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def setUp(self, *args, **kwargs):
|
||||
super(DB2BackupTests, self).setUp()
|
||||
self.exec_timeout_patch = patch.object(utils, 'execute_with_timeout')
|
||||
self.exec_timeout_patch.start()
|
||||
@ -983,7 +1010,12 @@ class DB2BackupTests(trove_testtools.TestCase):
|
||||
|
||||
class DB2RestoreTests(trove_testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service, 'run_command')
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def setUp(self, *args, **kwargs):
|
||||
super(DB2RestoreTests, self).setUp()
|
||||
|
||||
self.restore_runner = utils.import_class(
|
||||
|
@ -12,12 +12,16 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from mock import DEFAULT
|
||||
from mock import MagicMock
|
||||
from mock import patch
|
||||
from testtools.matchers import Is, Equals, Not
|
||||
|
||||
from trove.common.instance import ServiceStatuses
|
||||
from trove.guestagent import backup
|
||||
from trove.guestagent.common import configuration
|
||||
from trove.guestagent.common.configuration import ImportOverrideStrategy
|
||||
from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.datastore.experimental.db2 import (
|
||||
manager as db2_manager)
|
||||
from trove.guestagent.datastore.experimental.db2 import (
|
||||
@ -30,7 +34,11 @@ from trove.tests.unittests.guestagent.test_datastore_manager import \
|
||||
|
||||
class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
|
||||
def setUp(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2_service.DB2App, 'process_default_dbm_config')
|
||||
def setUp(self, *arg, **kwargs):
|
||||
super(GuestAgentDB2ManagerTest, self).setUp('db2')
|
||||
self.real_status = db2_service.DB2AppStatus.set_status
|
||||
|
||||
@ -58,6 +66,9 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
self.orig_delete_user = db2_service.DB2Admin.delete_user
|
||||
self.orig_update_hostname = db2_service.DB2App.update_hostname
|
||||
self.orig_backup_restore = backup.restore
|
||||
self.orig_init_config = db2_service.DB2App.init_config
|
||||
self.orig_update_overrides = db2_service.DB2App.update_overrides
|
||||
self.orig_remove_overrides = db2_service.DB2App.remove_overrides
|
||||
|
||||
def tearDown(self):
|
||||
super(GuestAgentDB2ManagerTest, self).tearDown()
|
||||
@ -78,6 +89,9 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
db2_service.DB2Admin.delete_user = self.orig_delete_user
|
||||
db2_service.DB2App.update_hostname = self.orig_update_hostname
|
||||
backup.restore = self.orig_backup_restore
|
||||
db2_service.DB2App.init_config = self.orig_init_config
|
||||
db2_service.DB2App.update_overrides = self.orig_update_overrides
|
||||
db2_service.DB2App.remove_overrides = self.orig_remove_overrides
|
||||
|
||||
def test_update_status(self):
|
||||
mock_status = MagicMock()
|
||||
@ -97,8 +111,9 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
def test_prepare_from_backup(self):
|
||||
self._prepare_dynamic(['db2'], backup_id='123backup')
|
||||
|
||||
@patch.object(configuration.ConfigurationManager, 'save_configuration')
|
||||
def _prepare_dynamic(self, packages=None, databases=None, users=None,
|
||||
config_content=None, device_path='/dev/vdb',
|
||||
config_content='MockContent', device_path='/dev/vdb',
|
||||
is_db_installed=True, backup_id=None, overrides=None):
|
||||
|
||||
backup_info = {'id': backup_id,
|
||||
@ -152,6 +167,9 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
backup.restore.assert_any_call(self.context,
|
||||
backup_info,
|
||||
'/home/db2inst1/db2inst1')
|
||||
self.assertTrue(
|
||||
self.manager.configuration_manager.save_configuration.called
|
||||
)
|
||||
|
||||
def test_restart(self):
|
||||
mock_status = MagicMock()
|
||||
@ -171,6 +189,12 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
db2_service.DB2App.stop_db.assert_any_call(
|
||||
do_not_start_on_reboot=False)
|
||||
|
||||
def test_start_db_with_conf_changes(self):
|
||||
with patch.object(db2_service.DB2App, 'start_db_with_conf_changes'):
|
||||
self.manager.start_db_with_conf_changes(self.context, 'something')
|
||||
db2_service.DB2App.start_db_with_conf_changes.assert_any_call(
|
||||
'something')
|
||||
|
||||
def test_create_database(self):
|
||||
mock_status = MagicMock()
|
||||
self.manager.appStatus = mock_status
|
||||
@ -228,13 +252,19 @@ class GuestAgentDB2ManagerTest(DatastoreManagerTest):
|
||||
self.assertThat(users, Equals(get_user_mock.return_value))
|
||||
get_user_mock.assert_any_call(username, hostname)
|
||||
|
||||
def test_reset_configuration(self):
|
||||
try:
|
||||
configuration = {'config_contents': 'some junk'}
|
||||
self.manager.reset_configuration(self.context, configuration)
|
||||
except Exception:
|
||||
self.fail("reset_configuration raised exception unexpectedly.")
|
||||
|
||||
def test_rpc_ping(self):
|
||||
output = self.manager.rpc_ping(self.context)
|
||||
self.assertTrue(output)
|
||||
|
||||
def test_update_update_overrides(self):
|
||||
configuration = {"DIAGSIZE": 50}
|
||||
db2_service.DB2App.update_overrides = MagicMock()
|
||||
self.manager.update_overrides(self.context, configuration, False)
|
||||
db2_service.DB2App.update_overrides.assert_any_call(self.context,
|
||||
configuration)
|
||||
|
||||
def test_reset_update_overrides(self):
|
||||
configuration = {}
|
||||
db2_service.DB2App.remove_overrides = MagicMock()
|
||||
self.manager.update_overrides(self.context, configuration, True)
|
||||
db2_service.DB2App.remove_overrides.assert_any_call()
|
||||
|
@ -3247,7 +3247,12 @@ class VerticaAppTest(trove_testtools.TestCase):
|
||||
|
||||
class DB2AppTest(trove_testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2service, 'run_command')
|
||||
@patch.object(db2service.DB2App, 'process_default_dbm_config')
|
||||
def setUp(self, *args, **kwargs):
|
||||
super(DB2AppTest, self).setUp()
|
||||
self.orig_utils_execute_with_timeout = (
|
||||
db2service.utils.execute_with_timeout)
|
||||
@ -3258,6 +3263,7 @@ class DB2AppTest(trove_testtools.TestCase):
|
||||
self.appStatus = FakeAppStatus(self.FAKE_ID,
|
||||
rd_instance.ServiceStatuses.NEW)
|
||||
self.db2App = db2service.DB2App(self.appStatus)
|
||||
self.db2App.init_config()
|
||||
dbaas.CONF.guest_id = self.FAKE_ID
|
||||
|
||||
def tearDown(self):
|
||||
@ -3279,7 +3285,12 @@ class DB2AppTest(trove_testtools.TestCase):
|
||||
self.db2App.stop_db()
|
||||
self.assert_reported_status(rd_instance.ServiceStatuses.NEW)
|
||||
|
||||
def test_restart_server(self):
|
||||
@patch.object(ImportOverrideStrategy, '_initialize_import_directory')
|
||||
@patch.multiple(operating_system, exists=DEFAULT, write_file=DEFAULT,
|
||||
chown=DEFAULT, chmod=DEFAULT)
|
||||
@patch.object(db2service, 'run_command')
|
||||
@patch.object(db2service.DB2App, 'process_default_dbm_config')
|
||||
def test_restart_server(self, *args, **kwargs):
|
||||
self.appStatus.set_next_status(rd_instance.ServiceStatuses.RUNNING)
|
||||
mock_status = MagicMock(return_value=None)
|
||||
app = db2service.DB2App(mock_status)
|
||||
@ -3302,6 +3313,35 @@ class DB2AppTest(trove_testtools.TestCase):
|
||||
self.db2App.start_db()
|
||||
self.assert_reported_status(rd_instance.ServiceStatuses.NEW)
|
||||
|
||||
@patch.object(ConfigurationManager, 'save_configuration')
|
||||
@patch.object(db2service.DB2App, 'start_db')
|
||||
def test_start_db_with_conf_changes(self, start_db, save_cfg):
|
||||
config = {'DIAGSIZE': '10'}
|
||||
self.db2App.start_db_with_conf_changes(config)
|
||||
start_db.assert_called_once_with(True)
|
||||
save_cfg.assert_called_once_with(config)
|
||||
|
||||
@patch.object(ConfigurationManager, 'apply_user_override')
|
||||
@patch.object(db2service.DB2App, '_apply_config')
|
||||
def test_update_overrides(self, apply_user_override, apply_config):
|
||||
overrides = {'DIAGSIZE': 50}
|
||||
context = MagicMock()
|
||||
self.db2App.update_overrides(context, overrides)
|
||||
apply_user_override.assert_called_once_with(overrides)
|
||||
apply_config.assert_called_once_with(overrides)
|
||||
|
||||
@patch.object(ConfigurationManager, 'get_user_override')
|
||||
@patch.object(ConfigurationManager, 'remove_user_override')
|
||||
@patch.object(db2service.DB2App, '_reset_config')
|
||||
def test_remove_overrides(self, reset_config, remove_user_override,
|
||||
get_user_override):
|
||||
overrides = {'DIAGSIZE': 50}
|
||||
get_user_override.return_value = overrides
|
||||
self.db2App.remove_overrides()
|
||||
get_user_override.assert_called_once()
|
||||
reset_config.assert_called_once_with(overrides)
|
||||
remove_user_override.assert_called_once()
|
||||
|
||||
|
||||
class DB2AdminTest(trove_testtools.TestCase):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user