update log analyzor code and fix some api bug.

Change-Id: I1247cd89e4dc44559016451e509e55f0541de480
This commit is contained in:
xiaodongwang 2014-08-29 11:44:22 -07:00
parent c80a75a3ed
commit 28451394e4
16 changed files with 1167 additions and 1198 deletions

View File

@ -20,6 +20,7 @@ import lockfile
import logging
from compass.actions import update_progress
from compass.db.api import database
from compass.tasks.client import celery
from compass.utils import daemonize
from compass.utils import flags
@ -28,11 +29,6 @@ from compass.utils import setting_wrapper as setting
from compass.utils import util
flags.add('clusters',
help=(
'clusters to clean, the format is as '
'clusterid:hostname1,hostname2,...;...'),
default='')
flags.add_bool('async',
help='run in async mode',
default=True)
@ -41,27 +37,25 @@ flags.add('run_interval',
default=setting.PROGRESS_UPDATE_INTERVAL)
def progress_update(cluster_hosts):
def progress_update():
"""entry function."""
if flags.OPTIONS.async:
celery.send_task('compass.tasks.update_progress', (cluster_hosts,))
celery.send_task('compass.tasks.update_progress')
else:
try:
update_progress.update_progress(cluster_hosts)
update_progress.update_progress()
except Exception as error:
logging.error('failed to update progress for cluster_hosts: %s',
cluster_hosts)
logging.error('failed to update progress')
logging.exception(error)
if __name__ == '__main__':
flags.init()
logsetting.init()
database.init()
logging.info('run progress update')
daemonize.daemonize(
functools.partial(
progress_update,
util.get_clusters_from_str(flags.OPTIONS.clusters)),
progress_update,
flags.OPTIONS.run_interval,
pidfile=lockfile.FileLock('/var/run/progress_update.pid'),
stderr=open('/tmp/progress_update_err.log', 'w+'),

View File

@ -19,43 +19,15 @@
import logging
from compass.actions import util
from compass.db.api import database
from compass.db import models
from compass.db.api import adapter_holder as adapter_api
from compass.db.api import cluster as cluster_api
from compass.db.api import host as host_api
from compass.db.api import user as user_api
from compass.log_analyzor import progress_calculator
from compass.utils import setting_wrapper as setting
def _cluster_filter(cluster):
"""filter cluster."""
if not cluster.state:
logging.error('there is no state for cluster %s',
cluster.id)
return False
if cluster.state.state != 'INSTALLING':
logging.error('the cluster %s state %s is not installing',
cluster.id, cluster.state.state)
return False
return True
def _host_filter(host):
"""filter host."""
if not host.state:
logging.error('there is no state for host %s',
host.id)
return False
if host.state.state != 'INSTALLING':
logging.error('the host %s state %s is not installing',
host.id, host.state.state)
return False
return True
def update_progress(cluster_hosts):
def update_progress():
"""Update status and installing progress of the given cluster.
:param cluster_hosts: clusters and hosts in each cluster to update.
@ -79,54 +51,234 @@ def update_progress(cluster_hosts):
'failed to acquire lock to calculate installation progress')
return
logging.info('update installing progress of cluster_hosts: %s',
cluster_hosts)
os_names = {}
distributed_systems = {}
os_installers = {}
package_installers = {}
with database.session() as session:
clusters = session.query(models.Cluster).all()
for cluster in clusters:
clusterid = cluster.id
logging.info('update installing progress')
adapter = cluster.adapter
os_installer = adapter.adapter_os_installer
if os_installer:
os_installers[clusterid] = os_installer.name
else:
os_installers[clusterid] = None
package_installer = adapter.adapter_package_installer
if package_installer:
package_installers[clusterid] = package_installer.name
else:
package_installers[clusterid] = None
user = user_api.get_user_object(setting.COMPASS_ADMIN_EMAIL)
hosts = host_api.list_hosts(user)
host_mapping = {}
for host in hosts:
if 'id' not in host:
logging.error('id is not in host %s', host)
continue
host_id = host['id']
if 'os_name' not in host:
logging.error('os_name is not in host %s', host)
continue
if 'os_installer' not in host:
logging.error('os_installer is not in host %s', host)
continue
host_dirname = setting.HOST_INSTALLATION_LOGDIR_NAME
if host_dirname not in host:
logging.error(
'%s is not in host %s', host_dirname, host
)
continue
host_state = host_api.get_host_state(user, host_id)
if 'state' not in host_state:
logging.error('state is not in host state %s', host_state)
continue
if host_state['state'] == 'INSTALLING':
host_log_histories = host_api.get_host_log_histories(
user, host_id
)
host_log_history_mapping = {}
for host_log_history in host_log_histories:
if 'filename' not in host_log_history:
logging.error(
'filename is not in host log history %s',
host_log_history
)
continue
host_log_history_mapping[
host_log_history['filename']
] = host_log_history
host_mapping[host_id] = (
host, host_state, host_log_history_mapping
)
else:
logging.info(
'ignore host state %s since it is not in installing',
host_state
)
adapters = adapter_api.list_adapters(user)
adapter_mapping = {}
for adapter in adapters:
if 'id' not in adapter:
logging.error(
'id not in adapter %s', adapter
)
continue
if 'package_installer' not in adapter:
logging.info(
'package_installer not in adapter %s', adapter
)
continue
adapter_id = adapter['id']
adapter_mapping[adapter_id] = adapter
clusters = cluster_api.list_clusters(user)
cluster_mapping = {}
for cluster in clusters:
if 'id' not in cluster:
logging.error('id not in cluster %s', cluster)
continue
cluster_id = cluster['id']
if 'adapter_id' not in cluster:
logging.error(
'adapter_id not in cluster %s',
cluster
)
continue
cluster_state = cluster_api.get_cluster_state(user, cluster_id)
if 'state' not in cluster_state:
logging.error('state not in cluster state %s', cluster_state)
continue
cluster_mapping[cluster_id] = (cluster, cluster_state)
clusterhosts = cluster_api.list_clusterhosts(user)
clusterhost_mapping = {}
for clusterhost in clusterhosts:
if 'clusterhost_id' not in clusterhost:
logging.error(
'clusterhost_id not in clusterhost %s',
clusterhost
)
continue
clusterhost_id = clusterhost['clusterhost_id']
if 'distributed_system_name' not in clusterhost:
logging.error(
'distributed_system_name is not in clusterhost %s',
clusterhost
)
continue
clusterhost_dirname = setting.CLUSTERHOST_INATALLATION_LOGDIR_NAME
if clusterhost_dirname not in clusterhost:
logging.error(
'%s is not in clusterhost %s',
clusterhost_dirname, clusterhost
)
continue
if 'cluster_id' not in clusterhost:
logging.error(
'cluster_id not in clusterhost %s',
clusterhost
)
continue
cluster_id = clusterhost['cluster_id']
if cluster_id not in cluster_mapping:
logging.info(
'ignore clusterhost %s '
'since the cluster_id '
'is not in cluster_mapping %s',
clusterhost, cluster_mapping
)
continue
cluster, _ = cluster_mapping[cluster_id]
adapter_id = cluster['adapter_id']
if adapter_id not in adapter_mapping:
logging.info(
'ignore clusterhost %s '
'since the adapter_id %s '
'is not in adaper_mapping %s',
clusterhost, adapter_id, adapter_mapping
)
adapter = adapter_mapping[adapter_id]
package_installer = adapter['package_installer']
clusterhost['package_installer'] = package_installer
clusterhost_state = cluster_api.get_clusterhost_self_state(
user, clusterhost_id
)
if 'state' not in clusterhost_state:
logging.error(
'state not in clusterhost_state %s',
clusterhost_state
)
continue
if clusterhost_state['state'] == 'INSTALLING':
clusterhost_log_histories = (
cluster_api.get_clusterhost_log_histories(
user, clusterhost_id
)
)
clusterhost_log_history_mapping = {}
for clusterhost_log_history in clusterhost_log_histories:
if 'filename' not in clusterhost_log_history:
logging.error(
'filename not in clusterhost_log_history %s',
clusterhost_log_history
)
continue
clusterhost_log_history_mapping[
clusterhost_log_history['filename']
] = clusterhost_log_history
clusterhost_mapping[clusterhost_id] = (
clusterhost, clusterhost_state,
clusterhost_log_history_mapping
)
else:
logging.info(
'ignore clusterhost state %s '
'since it is not in installing',
clusterhost_state
)
distributed_system_name = cluster.distributed_system_name
os_name = cluster.os_name
os_names[clusterid] = os_name
distributed_systems[clusterid] = distributed_system_name
clusterhosts = cluster.clusterhosts
hostids = [clusterhost.host.id for clusterhost in clusterhosts]
cluster_hosts.update({clusterid: hostids})
logging.info(
'update progress for '
'os_installers %s,'
'os_names %s,'
'package_installers %s,'
'distributed_systems %s,'
'cluster_hosts %s',
os_installers,
os_names,
package_installers,
distributed_systems,
cluster_hosts
)
progress_calculator.update_progress(
os_installers,
os_names,
package_installers,
distributed_systems,
cluster_hosts)
progress_calculator.update_host_progress(
host_mapping)
for host_id, (host, host_state, host_log_history_mapping) in (
host_mapping.items()
):
host_api.update_host_state(
user, host_id,
percentage=host_state.get('percentage', 0),
message=host_state.get('message', ''),
severity=host_state.get('severity', 'INFO')
)
for filename, host_log_history in (
host_log_history_mapping.items()
):
host_api.add_host_log_history(
user, host_id, filename=filename,
position=host_log_history.get('position', 0),
percentage=host_log_history.get('percentage', 0),
partial_line=host_log_history.get('partial_line', ''),
message=host_log_history.get('message', ''),
severity=host_log_history.get('severity', 'INFO'),
line_matcher_name=host_log_history.get(
'line_matcher_name', 'start'
)
)
progress_calculator.update_clusterhost_progress(
clusterhost_mapping)
for (
clusterhost_id,
(clusterhost, clusterhost_state, clusterhost_log_history_mapping)
) in (
clusterhost_mapping.items()
):
cluster_api.update_clusterhost_state(
user, clusterhost_id,
percentage=clusterhost_state.get('percentage', 0),
message=clusterhost_state.get('message', ''),
severity=clusterhost_state.get('severity', 'INFO')
)
for filename, clusterhost_log_history in (
clusterhost_log_history_mapping.items()
):
cluster_api.add_clusterhost_log_history(
user, clusterhost_id, filename=filename,
position=clusterhost_log_history.get('position', 0),
percentage=clusterhost_log_history.get('percentage', 0),
partial_line=clusterhost_log_history.get(
'partial_line', ''),
message=clusterhost_log_history.get('message', ''),
severity=clusterhost_log_history.get('severity', 'INFO'),
line_matcher_name=(
clusterhost_log_history.get(
'line_matcher_name', 'start'
)
)
)
progress_calculator.update_cluster_progress(
cluster_mapping)
for cluster_id, (cluster, cluster_state) in cluster_mapping.items():
cluster_api.update_cluster_state(
user, cluster_id
)

View File

@ -82,12 +82,12 @@ RESP_CLUSTERHOST_DEPLOYED_CONFIG_FIELDS = [
'updated_at'
]
RESP_STATE_FIELDS = [
'id', 'state', 'percentage', 'message',
'id', 'state', 'percentage', 'message', 'severity'
'status',
'created_at', 'updated_at'
]
RESP_CLUSTERHOST_STATE_FIELDS = [
'id', 'state', 'percentage', 'message',
'id', 'state', 'percentage', 'message', 'severity',
'created_at', 'updated_at'
]
RESP_REVIEW_FIELDS = [
@ -125,11 +125,24 @@ UPDATED_CLUSTERHOST_DEPLOYED_CONFIG_FIELDS = [
'deployed_package_config'
]
UPDATED_CLUSTERHOST_STATE_FIELDS = [
'state', 'percentage', 'message'
'state', 'percentage', 'message', 'severity'
]
UPDATED_CLUSTER_STATE_FIELDS = [
'state'
]
RESP_CLUSTERHOST_LOG_FIELDS = [
'clusterhost_id', 'id', 'host_id', 'cluster_id',
'filename', 'position', 'partial_line',
'percentage',
'message', 'severity', 'line_matcher_name'
]
ADDED_CLUSTERHOST_LOG_FIELDS = [
'filename'
]
UPDATED_CLUSTERHOST_LOG_FIELDS = [
'position', 'partial_line', 'percentage',
'message', 'severity', 'line_matcher_name'
]
@utils.supported_filters(optional_support_keys=SUPPORTED_FIELDS)
@ -465,6 +478,17 @@ def add_clusterhost_internal(
reinstall_os_set=kwargs.get('reinstall_os', False),
exception_when_not_editable=False
):
if 'name' in host_dict:
hostname = host_dict['name']
host_by_name = utils.get_db_object(
session, models.Host, False, name=hostname
)
if host_by_name:
raise exception.InvalidParameter(
'host name %s exists in host %s' % (
hostname, host_by_name
)
)
utils.update_db_object(
session, host,
**host_dict
@ -472,6 +496,17 @@ def add_clusterhost_internal(
else:
logging.info('host %s is not editable', host.name)
else:
if 'name' in host_dict:
hostname = host_dict['name']
host = utils.get_db_object(
session, models.Host, False, name=hostname
)
if host:
raise exception.InvalidParameter(
'host name %s exists in host %s' % (
hostname, host
)
)
host = utils.add_db_object(
session, models.Host, False, machine_id,
os=cluster.os,
@ -1284,6 +1319,26 @@ def get_cluster_host_state(
).state_dict()
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_GET_CLUSTERHOST_STATE
)
@utils.wrap_to_dict(RESP_CLUSTERHOST_STATE_FIELDS)
def get_cluster_host_self_state(
session, getter, cluster_id, host_id, **kwargs
):
"""Get clusterhost state info."""
clusterhost = utils.get_db_object(
session, models.ClusterHost,
cluster_id=cluster_id, host_id=host_id
)
return utils.get_db_object(
session, models.ClusterHostState,
id=clusterhost.clusterhost_id
)
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission_in_session(
@ -1299,6 +1354,21 @@ def get_clusterhost_state(
).state_dict()
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_GET_CLUSTERHOST_STATE
)
@utils.wrap_to_dict(RESP_CLUSTERHOST_STATE_FIELDS)
def get_clusterhost_self_state(
session, getter, clusterhost_id, **kwargs
):
"""Get clusterhost state info."""
return utils.get_db_object(
session, models.ClusterHostState, id=clusterhost_id
)
@utils.supported_filters(
optional_support_keys=UPDATED_CLUSTERHOST_STATE_FIELDS
)
@ -1355,3 +1425,122 @@ def update_cluster_state(
)
utils.update_db_object(session, cluster.state, **kwargs)
return cluster.state_dict()
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def get_cluster_host_log_histories(
session, getter, cluster_id, host_id, **kwargs
):
"""Get clusterhost log history."""
return utils.list_db_objects(
session, models.ClusterHostLogHistory,
cluster_id=cluster_id, host_id=host_id
)
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def get_clusterhost_log_histories(session, getter, clusterhost_id, **kwargs):
"""Get clusterhost log history."""
return utils.list_db_objects(
session, models.ClusterHostLogHistory, clusterhost_id=clusterhost_id
)
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def get_cluster_host_log_history(
session, getter, cluster_id, host_id, filename, **kwargs
):
"""Get clusterhost log history."""
return utils.get_db_object(
session, models.ClusterHostLogHistory,
cluster_id=cluster_id, host_id=host_id, filename=filename
)
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def get_clusterhost_log_history(
session, getter, clusterhost_id, filename, **kwargs
):
"""Get host log history."""
return utils.get_db_object(
session, models.ClusterHostLogHistory,
clusterhost_id=clusterhost_id, filename=filename
)
@utils.supported_filters(
optional_support_keys=UPDATED_CLUSTERHOST_LOG_FIELDS
)
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def update_host_log_history(
session, updater, cluster_id, host_id, filename, **kwargs
):
"""Update a host log history."""
cluster_host_log_history = utils.get_db_object(
session, models.ClusterHostLogHistory,
cluster_id=cluster_id, host_id=host_id, filename=filename
)
return utils.update_db_object(session, cluster_host_log_history, **kwargs)
@utils.supported_filters(
optional_support_keys=UPDATED_CLUSTERHOST_LOG_FIELDS
)
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def update_clusterhost_log_history(
session, updater, clusterhost_id, filename, **kwargs
):
"""Update a host log history."""
clusterhost_log_history = utils.get_db_object(
session, models.ClusterHostLogHistory,
clusterhost_id=clusterhost_id, filename=filename
)
return utils.update_db_object(session, clusterhost_log_history, **kwargs)
@utils.supported_filters(
ADDED_CLUSTERHOST_LOG_FIELDS,
optional_support_keys=UPDATED_CLUSTERHOST_LOG_FIELDS
)
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def add_clusterhost_log_history(
session, creator, clusterhost_id, exception_when_existing=False,
filename=None, **kwargs
):
"""add a host log history."""
return utils.add_db_object(
session, models.ClusterHostLogHistory, exception_when_existing,
clusterhost_id, filename, **kwargs
)
@utils.supported_filters(
ADDED_CLUSTERHOST_LOG_FIELDS,
optional_support_keys=UPDATED_CLUSTERHOST_LOG_FIELDS
)
@database.run_in_session()
@utils.wrap_to_dict(RESP_CLUSTERHOST_LOG_FIELDS)
def add_cluster_host_log_history(
session, creator, cluster_id, host_id, exception_when_existing=False,
filename=None, **kwargs
):
"""add a host log history."""
clusterhost = utils.get_db_object(
session, models.ClusterHost,
cluster_id=cluster_id, host_id=host_id
)
return utils.add_db_object(
session, models.ClusterHostLogHistory, exception_when_existing,
clusterhost.clusterhost_id, filename, **kwargs
)

View File

@ -83,10 +83,21 @@ IGNORED_NETWORK_FIELDS = [
'interface'
]
RESP_STATE_FIELDS = [
'id', 'state', 'percentage', 'message'
'id', 'state', 'percentage', 'message', 'severity'
]
UPDATED_STATE_FIELDS = [
'state', 'percentage', 'message'
'state', 'percentage', 'message', 'severity'
]
RESP_LOG_FIELDS = [
'id', 'filename', 'position', 'partial_line', 'percentage',
'message', 'severity', 'line_matcher_name'
]
ADDED_LOG_FIELDS = [
'filename'
]
UPDATED_LOG_FIELDS = [
'position', 'partial_line', 'percentage',
'message', 'severity', 'line_matcher_name'
]
@ -255,6 +266,17 @@ def _update_host(session, updater, host_id, **kwargs):
session, host, updater,
reinstall_os_set=kwargs.get('reinstall_os', False)
)
if 'name' in kwargs:
hostname = kwargs['name']
host_by_name = utils.get_db_object(
session, models.Host, False, name=hostname
)
if host_by_name and host_by_name.id != host.id:
raise exception.InvalidParameter(
'hostname %s is already exists in host %s' % (
hostname, host_by_name
)
)
return utils.update_db_object(session, host, **kwargs)
@ -500,7 +522,6 @@ def _add_host_network(
host = utils.get_db_object(
session, models.Host, id=host_id
)
is_host_editable(session, host, creator)
ip_int = long(netaddr.IPAddress(ip))
host_network = utils.get_db_object(
session, models.HostNetwork, False,
@ -508,8 +529,11 @@ def _add_host_network(
)
if host_network:
raise exception.InvalidParameter(
'ip %s exists in database' % ip
'ip %s exists in host network %s' % (
ip, host_network
)
)
is_host_editable(session, host, creator)
return utils.add_db_object(
session, models.HostNetwork,
exception_when_existing,
@ -597,6 +621,24 @@ def update_host_network(
host_id, host_network_id
)
)
if 'ip' in kwargs:
ip = kwargs['ip']
ip_int = long(netaddr.IPAddress(ip))
host_network_by_ip = utils.get_db_object(
session, models.HostNetwork, False,
ip_int=ip_int
)
if host_network_by_ip and host_network_by_ip.id != host_network.id:
raise exception.InvalidParameter(
'ip %s exist in host network %s' % (
ip, host_network_by_ip
)
)
if host_network:
raise exception.InvalidParameter(
'ip %s exists in database' % ip
)
is_host_editable(session, host_network.host, updater)
return utils.update_db_object(session, host_network, **kwargs)
@ -687,6 +729,53 @@ def update_host_state(session, updater, host_id, **kwargs):
return host.state_dict()
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_LOG_FIELDS)
def get_host_log_histories(session, getter, host_id, **kwargs):
"""Get host log history."""
return utils.list_db_objects(
session, models.HostLogHistory, id=host_id
)
@utils.supported_filters([])
@database.run_in_session()
@utils.wrap_to_dict(RESP_LOG_FIELDS)
def get_host_log_history(session, getter, host_id, filename, **kwargs):
"""Get host log history."""
return utils.get_db_object(
session, models.HostLogHistory, id=host_id, filename=filename
)
@utils.supported_filters(optional_support_keys=UPDATED_LOG_FIELDS)
@database.run_in_session()
@utils.wrap_to_dict(RESP_LOG_FIELDS)
def update_host_log_history(session, updater, host_id, filename, **kwargs):
"""Update a host log history."""
host_log_history = utils.get_db_object(
session, models.HostLogHistory, id=host_id, filename=filename
)
return utils.update_db_object(session, host_log_history, **kwargs)
@utils.supported_filters(
ADDED_LOG_FIELDS,
optional_support_keys=UPDATED_LOG_FIELDS)
@database.run_in_session()
@utils.wrap_to_dict(RESP_LOG_FIELDS)
def add_host_log_history(
session, creator, host_id, exception_when_existing=False,
filename=None, **kwargs
):
"""add a host log history."""
return utils.add_db_object(
session, models.HostLogHistory, exception_when_existing,
host_id, filename, **kwargs
)
@utils.supported_filters(optional_support_keys=['poweron'])
@database.run_in_session()
@user_api.check_user_permission_in_session(

View File

@ -265,9 +265,6 @@ def supported_filters(
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **filters):
logging.info('support_keys: %s', support_keys)
logging.info('optional_support_keys: %s', optional_support_keys)
logging.info('ignore_support_keys: %s', ignore_support_keys)
must_support_keys = set(support_keys)
all_support_keys = must_support_keys | set(optional_support_keys)
filter_keys = set(filters)
@ -653,6 +650,6 @@ def check_switch_credentials(credentials):
)
else:
logging.debug(
'function %s is not defined in %s',
key_check_func_name, this_module
'function %s is not defined',
key_check_func_name
)

View File

@ -481,6 +481,7 @@ class ClusterHostState(BASE, StateMixin):
)
def update(self):
super(ClusterHostState, self).update()
host_state = self.clusterhost.host.state
if self.state == 'INITIALIZED':
if host_state.state in ['UNINITIALIZED']:
@ -494,7 +495,6 @@ class ClusterHostState(BASE, StateMixin):
if host_state.state != 'SUCCESSFUL':
host_state.state = 'SUCCESSFUL'
host_state.update()
super(ClusterHostState, self).update()
class ClusterHost(BASE, TimestampMixin, HelperMixin):
@ -689,13 +689,27 @@ class ClusterHost(BASE, TimestampMixin, HelperMixin):
def state_dict(self):
cluster = self.cluster
host = self.host
host_state = host.state_dict()
if not cluster.distributed_system:
return host_state
clusterhost_state = self.state.to_dict()
if clusterhost_state['state'] in ['ERROR', 'SUCCESSFUL']:
return clusterhost_state
if (
not cluster.distributed_system or
host.state.state != 'SUCCESSFUL'
clusterhost_state['state'] in 'INSTALLING' and
clusterhost_state['percentage'] > 0
):
return host.state_dict()
else:
return self.state.to_dict()
clusterhost_state['percentage'] = min(
1.0, (
0.5 + clusterhost_state['percentage'] / 2
)
)
return clusterhost_state
host_state['percentage'] = host_state['percentage'] / 2
if host_state['state'] == 'SUCCESSFUL':
host_state['state'] = 'INSTALLING'
return host_state
def to_dict(self):
dict_info = self.host.to_dict()
@ -729,6 +743,7 @@ class HostState(BASE, StateMixin):
)
def update(self):
super(HostState, self).update()
host = self.host
if self.state == 'INSTALLING':
host.reinstall_os = False
@ -752,7 +767,6 @@ class HostState(BASE, StateMixin):
]:
clusterhost.state = 'INITIALIZED'
clusterhost.state.update()
super(HostState, self).update()
class Host(BASE, TimestampMixin, HelperMixin):
@ -955,7 +969,7 @@ class ClusterState(BASE, StateMixin):
cluster = self.cluster
clusterhosts = cluster.clusterhosts
self.total_hosts = len(clusterhosts)
if self.state in ['UNINITIALIZED', 'INITIALIZED']:
if self.state in ['UNINITIALIZED', 'INITIALIZED', 'INSTALLING']:
self.installing_hosts = 0
self.failed_hosts = 0
self.completed_hosts = 0
@ -981,16 +995,19 @@ class ClusterState(BASE, StateMixin):
elif clusterhost_state == 'SUCCESSFUL':
self.completed_hosts += 1
if self.total_hosts:
self.percentage = (
float(self.completed_hosts)
/
float(self.total_hosts)
)
if self.completed_hosts == self.total_hosts:
self.percentage = 1.0
else:
self.percentage = (
float(self.completed_hosts)
/
float(self.total_hosts)
)
self.message = (
'total %s, installing %s, completed: %s, error %s'
) % (
self.total_hosts, self.completed_hosts,
self.installing_hosts, self.failed_hosts
self.total_hosts, self.installing_hosts,
self.completed_hosts, self.failed_hosts
)
if self.failed_hosts:
self.severity = 'ERROR'

View File

@ -16,71 +16,60 @@
.. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com>
"""
import datetime
import logging
import re
from compass.db.api import cluster as cluster_api
from compass.db.api import database
from compass.db.api import host as host_api
from compass.db.api import user as user_api
from compass.db.models import Cluster
from compass.db.models import ClusterHost
from compass.db.models import Host
from compass.log_analyzor.line_matcher import Progress
from compass.utils import setting_wrapper as setting
class AdapterItemMatcher(object):
"""Progress matcher for the os installing or package installing."""
def __init__(self, file_matchers):
self.file_matchers_ = file_matchers
self.min_progress_ = 0.0
self.max_progress_ = 1.0
def update_progress_range(self, min_progress, max_progress):
"""update min_progress and max_progress."""
self.min_progress_ = min_progress
self.max_progress_ = max_progress
for file_matcher in self.file_matchers_:
file_matcher.update_absolute_progress_range(
self.min_progress_, self.max_progress_)
def __str__(self):
return '%s[file_matchers: %s, min_progress: %s, max_progress: %s]' % (
self.__class__.__name__, self.file_matchers_,
self.min_progress_, self.max_progress_)
self.__class__.__name__, self.file_matchers_
)
def update_progress(self, fullname, progress):
def update_progress(
self, file_reader_factory, name, state, log_history_mapping
):
"""Update progress.
:param fullname: the fullname of the installing host.
:type fullname: str
:param name: the fullname of the installing host.
:type name: str
:param progress: Progress instance to update.
"""
for file_matcher in self.file_matchers_:
file_matcher.update_progress(fullname, progress)
filename = file_matcher.filename_
if filename not in log_history_mapping:
log_history_mapping[filename] = {
'filename': filename,
'partial_line': '',
'position': 0,
'line_matcher_name': 'start',
'percentage': 0.0,
'message': '',
'severity': 'INFO'
}
log_history = log_history_mapping[filename]
file_matcher.update_progress(
file_reader_factory, name, state, log_history
)
class OSMatcher(object):
"""Progress matcher for os installer."""
def __init__(self, os_installer_name, os_pattern,
item_matcher, min_progress, max_progress):
if not (0.0 <= min_progress <= max_progress <= 1.0):
raise IndexError('%s restriction not mat:'
'0.0 <= min_progress(%s) '
'<= max_progress(%s) <= 1.0' % (
self.__class__.__name__,
min_progress, max_progress))
def __init__(
self, os_installer_name,
os_pattern, item_matcher,
file_reader_factory
):
self.name_ = os_installer_name
self.os_regex_ = re.compile(os_pattern)
self.matcher_ = item_matcher
self.matcher_.update_progress_range(min_progress, max_progress)
self.file_reader_factory_ = file_reader_factory
def __repr__(self):
return '%s[name:%s, os_pattern:%s, matcher:%s]' % (
@ -97,425 +86,41 @@ class OSMatcher(object):
self.os_regex_.match(os_name)
])
def update_progress(self, fullname, progress):
def update_progress(self, name, state, log_history_mapping):
"""Update progress."""
logging.debug('selfname: %s', self.name_)
self.matcher_.update_progress(fullname, progress)
self.matcher_.update_progress(
self.file_reader_factory_, name, state, log_history_mapping)
class PackageMatcher(object):
"""Progress matcher for package installer."""
def __init__(self, package_installer_name, target_system,
item_matcher, min_progress, max_progress):
if not (0.0 <= min_progress <= max_progress <= 1.0):
raise IndexError('%s restriction not mat:'
'0.0 <= min_progress(%s) '
'<= max_progress(%s) <= 1.0' % (
self.__class__.__name__,
min_progress, max_progress))
def __init__(
self, package_installer_name, distributed_system_pattern,
item_matcher, file_reader_factory
):
self.name_ = re.compile(package_installer_name)
self.target_system_ = target_system
self.ds_regex_ = re.compile(distributed_system_pattern)
self.matcher_ = item_matcher
self.matcher_.update_progress_range(min_progress, max_progress)
self.file_reader_factory_ = file_reader_factory
def __repr__(self):
return '%s[name:%s, target_system:%s, matcher:%s]' % (
self.__class__.__name__, self.name_,
self.target_system_, self.matcher_)
def match(self, package_installer_name, target_system):
def match(self, package_installer_name, distributed_system_name):
"""Check if the package matcher is acceptable."""
if package_installer_name is None:
return False
else:
return all([
self.name_.match(package_installer_name),
self.target_system_ == target_system
self.ds_regex_.match(distributed_system_name)
])
def update_progress(self, fullname, progress):
def update_progress(self, name, state, log_history_mapping):
"""Update progress."""
self.matcher_.update_progress(fullname, progress)
class AdapterMatcher(object):
"""Adapter matcher to update adapter installing progress."""
def __init__(self, os_matcher, package_matcher):
self.os_matcher_ = os_matcher
self.package_matcher_ = package_matcher
def match(self, os_installer_name, os_name,
package_installer_name, target_system):
"""Check if the adapter matcher is acceptable.
:param os_installer_name: the os installer name.
:type os_installer_name: str
:param os_name: the os name.
:type os_name: str
:param package_installer_name: the package installer name.
:type package_installer_name: str
:param target_system: the target system to deploy
:type target_system: str
:returns: bool
.. note::
Return True if the AdapterMatcher can process the log files
generated from the os installation and package installation.
"""
return all([
self.os_matcher_.match(os_installer_name, os_name),
self.package_matcher_.match(
package_installer_name, target_system)])
def __str__(self):
return '%s[os_matcher:%s, package_matcher:%s]' % (
self.__class__.__name__,
self.os_matcher_, self.package_matcher_)
@classmethod
def _get_host_progress(cls, hostid):
"""Get Host Progress from HostState."""
session = database.current_session()
host = session.query(
Host
).filter_by(id=hostid).first()
if not host:
logging.error(
'there is no host for %s in Host', hostid)
return None, None, None
if not host.state:
logging.error('there is no related HostState for %s',
hostid)
return host.name, None, None
return (
host.name,
host.state.state,
Progress(host.state.percentage,
host.state.message,
host.state.severity))
@classmethod
def _get_clusterhost_progress(cls, hostid):
"""Get ClusterHost progress from ClusterHostState."""
session = database.current_session()
clusterhost = session.query(
ClusterHost
).filter_by(host_id=hostid).first()
if not clusterhost:
logging.error(
'there is no clusterhost for %s in ClusterHost',
hostid
)
return None, None, None
if not clusterhost.state:
logging.error(
'there is no related ClusterHostState for %s',
hostid
)
return clusterhost.name, None, None
return (
clusterhost.name,
clusterhost.state.state,
Progress(clusterhost.state.percentage,
clusterhost.state.message,
clusterhost.state.severity))
@classmethod
def _update_host_progress(cls, hostid, host_progress, updater):
"""Updates host progress to db."""
state = 'INSTALLING'
with database.session() as session:
host = session.query(
Host).filter_by(id=hostid).first()
if not host:
logging.error(
'there is no host for %s in table Host',
hostid
)
if not host.state:
logging.error(
'there is no related HostState for %s',
hostid
)
if host.state.percentage > host_progress.progress:
logging.error(
'host %s progress has not been increased'
' from %s to $s',
hostid, host.state, host_progress
)
return
if (
host.state.percentage == host_progress.progress and
host.state.message == host_progress.message
):
logging.info(
'host %s update ignored due to same progress'
'in database',
hostid
)
return
if host.state.percentage >= 1.0:
state = 'SUCCESSFUL'
if host.state.severity == 'ERROR':
state = 'ERROR'
logging.info('update host state by %s', updater)
host_api.update_host_state(
updater,
hostid,
state=state,
percentage=host_progress.progress,
message=host_progress.message
self.matcher_.update_progress(
self.file_reader_factory_, name, state, log_history_mapping
)
logging.debug(
'update host %s state %s',
hostid, state)
@classmethod
def _update_clusterhost_progress(
cls,
clusterid,
hostid,
clusterhost_progress,
updater
):
clusterhost_state = 'INSTALLING'
with database.session() as session:
clusterhost = session.query(
ClusterHost).filter_by(host_id=hostid).first()
if not clusterhost.state:
logging.error(
'ClusterHost state not found for %s',
hostid)
if clusterhost.state.percentage > clusterhost_progress.progress:
logging.error(
'clusterhost %s state has not been increased'
' from %s to %s',
hostid, clusterhost.state, clusterhost_progress
)
return
if (
clusterhost.state.percentage ==
clusterhost_progress.progress and
clusterhost.state.message == clusterhost_progress.message
):
logging.info(
'clusterhost %s update ignored due to same progress'
'in database',
hostid
)
return
if clusterhost.state.percentage >= 1.0:
clusterhost_state = 'SUCCESSFUL'
if clusterhost.state.severity == 'ERROR':
clusterhost_state = 'ERROR'
logging.info('updatge clusterhost state by %s', updater)
cluster_api.update_cluster_host_state(
updater,
clusterid,
hostid,
state=clusterhost_state,
percentage=clusterhost_progress.progress,
message=clusterhost_progress.message
)
logging.debug(
'update clusterhost %s state %s',
hostid, clusterhost_state)
@classmethod
def _update_cluster_progress(cls, clusterid):
"""Update cluster installing progress to database.
.. note::
The function should be called in the database session.
"""
session = database.current_session()
cluster = session.query(
Cluster).filter_by(id=clusterid).first()
if not cluster:
logging.error(
'there is no cluster for %s in Cluster',
clusterid)
return
if not cluster.state:
logging.error(
'there is no ClusterState for %s',
clusterid)
if cluster.state.state != 'INSTALLING':
logging.error('cluster %s is not in INSTALLING state',
clusterid)
return
cluster_progress = 0.0
cluster_messages = {}
cluster_severities = set([])
cluster_installing_hosts = 0
cluster_completed_hosts = 0
cluster_failed_hosts = 0
clusterhosts = cluster.clusterhosts
if not cluster.distributed_system:
hosts = [clusterhost.host for clusterhost in clusterhosts]
for host in hosts:
if host.state:
cluster_progress += host.state.percentage
if host.state.state == 'INSTALLING':
cluster_installing_hosts += 1
elif host.state.state == 'SUCCESSFUL':
cluster_completed_hosts += 1
elif host.state.state == 'ERROR':
cluster_failed_hosts += 1
if host.state.message:
cluster_messages[host.name] = host.state.message
if host.state.severity:
cluster_severities.add(host.state.severity)
else:
for clusterhost in clusterhosts:
if clusterhost.state:
cluster_progress += clusterhost.state.percentage
if clusterhost.state.state == 'INSTALLING':
cluster_installing_hosts += 1
elif clusterhost.state.state == 'SUCCESSFUL':
cluster_completed_hosts += 1
elif clusterhost.state.state == 'ERROR':
cluster_failed_hosts += 1
if clusterhost.state.message:
cluster_messages[clusterhost.name] = (
clusterhost.state.message
)
if clusterhost.state.severity:
cluster_severities.add(clusterhost.state.severity)
cluster.state.percentage = (
float(cluster_completed_hosts) / float(cluster.state.total_hosts)
)
cluster.state.message = '\n'.join(
[
'%s: %s' % (hostname, message)
for hostname, message in cluster_messages.items()
]
)
for severity in ['ERROR', 'WARNING', 'INFO']:
if severity in cluster_severities:
cluster.state.severity = severity
break
if cluster.state.percentage >= 1.0:
cluster.state.state = 'SUCCESSFUL'
if cluster.state.severity == 'ERROR':
cluster.state.state = 'ERROR'
cluster.state.installing_hosts = cluster_installing_hosts
cluster.state.total_hosts = len(clusterhosts)
cluster.state.failed_hosts = cluster_failed_hosts
cluster.state.completed_hosts = cluster_completed_hosts
logging.debug(
'update cluster %s state %s',
clusterid, cluster.state)
def update_progress(self, clusterid, hostids):
host_progresses = {}
clusterhost_progresses = {}
updater = user_api.get_user_object(
setting.COMPASS_ADMIN_EMAIL
)
with database.session():
for hostid in hostids:
host_name, host_state, host_progress = \
self._get_host_progress(hostid)
_, clusterhost_state, clusterhost_progress = \
self._get_clusterhost_progress(hostid)
if (not host_name or
not host_progress or
not clusterhost_progress):
logging.error(
'nothing to update host %s',
host_name)
continue
logging.debug('got host %s host_state: %s '
'host_progress: %s, '
'clusterhost_state: %s, '
'clusterhost_progress: %s ',
host_name,
host_state,
host_progress,
clusterhost_state,
clusterhost_progress)
host_progresses[hostid] = (
host_name, host_state, host_progress)
clusterhost_progresses[hostid] = (
host_name, clusterhost_state, clusterhost_progress)
for hostid, host_value in host_progresses.items():
host_name, host_state, host_progress = host_value
if (host_state == 'INSTALLING' and
host_progress.progress < 1.0):
self.os_matcher_.update_progress(
host_name, host_progress)
else:
logging.error(
'there is no need to update host %s '
'progress: state %s progress %s',
host_name, host_state, host_progress)
for hostid, clusterhost_value in clusterhost_progresses.items():
host_name, clusterhost_state, clusterhost_progress = \
clusterhost_value
if (clusterhost_state == 'INSTALLING' and
clusterhost_progress.progress < 1.0):
self.package_matcher_.update_progress(
host_name, clusterhost_progress)
else:
logging.error(
'no need to update clusterhost %s'
'progress: state %s progress %s',
host_name, clusterhost_state, clusterhost_progress)
for hostid in hostids:
if hostid not in host_progresses:
continue
if hostid not in clusterhost_progresses:
continue
_, _, host_progress = host_progresses[hostid]
_, _, clusterhost_progress = clusterhost_progresses[hostid]
self._update_host_progress(hostid, host_progress, updater)
self._update_clusterhost_progress(
clusterid,
hostid,
clusterhost_progress,
updater
)
with database.session():
self._update_cluster_progress(clusterid)

View File

@ -19,9 +19,6 @@
import logging
import os.path
from compass.db.api import database
from compass.db.models import LogProgressingHistory
from compass.log_analyzor.line_matcher import Progress
from compass.utils import setting_wrapper as setting
@ -83,114 +80,43 @@ class FileReader(object):
it has read last time. and update the position when it finish
reading the log.
"""
def __init__(self, pathname):
def __init__(self, pathname, log_history):
self.pathname_ = pathname
self.position_ = 0
self.partial_line_ = ''
self.log_history_ = log_history
def __repr__(self):
return (
'%s[pathname:%s, position:%s, partial_line:%s]' % (
self.__class__.__name__, self.pathname_, self.position_,
self.partial_line_
'%s[pathname:%s, log_history:%s]' % (
self.__class__.__name__, self.pathname_,
self.log_history_
)
)
def get_history(self):
"""Get log file read history from database.
:returns: (line_matcher_name progress)
.. note::
The function should be called out of database session.
It reads the log_progressing_history table to get the
position in the log file it has read in last run,
the partial line of the log, the line matcher name
in the last run, the progress, the message and the
severity it has got in the last run.
"""
session = database.current_session()
history = session.query(
LogProgressingHistory
).filter_by(
pathname=self.pathname_
).first()
if history:
self.position_ = history.position
self.partial_line_ = history.partial_line
line_matcher_name = history.line_matcher_name
progress = Progress(history.percentage,
history.message,
history.severity)
else:
line_matcher_name = 'start'
progress = Progress(0.0, '', None)
return line_matcher_name, progress
def update_history(self, line_matcher_name, progress):
"""Update log_progressing_history table.
:param line_matcher_name: the line matcher name.
:param progress: Progress instance to record the installing progress.
.. note::
The function should be called out of database session.
It updates the log_processing_history table.
"""
session = database.current_session()
history = session.query(LogProgressingHistory).filter_by(
pathname=self.pathname_).first()
if history:
if history.position >= self.position_:
logging.error(
'%s history position %s is ahead of current '
'position %s',
self.pathname_,
history.position,
self.position_)
return
history.position = self.position_
history.partial_line = self.partial_line_
history.line_matcher_name = line_matcher_name
history.progress = progress.progress
history.message = progress.message
history.severity = progress.severity
else:
history = LogProgressingHistory(
pathname=self.pathname_, position=self.position_,
partial_line=self.partial_line_,
line_matcher_name=line_matcher_name,
percentage=progress.progress,
message=progress.message,
severity=progress.severity)
session.merge(history)
logging.debug('update file %s to history %s',
self.pathname_, history)
def readline(self):
"""Generate each line of the log file."""
old_position = self.position_
old_position = self.log_history_['position']
position = self.log_history_['position']
partial_line = self.log_history_['partial_line']
try:
with open(self.pathname_) as logfile:
logfile.seek(self.position_)
logfile.seek(position)
while True:
line = logfile.readline()
self.partial_line_ += line
partial_line += line
position = logfile.tell()
if position > self.position_:
self.position_ = position
if position > self.log_history_['position']:
self.log_history_['position'] = position
if self.partial_line_.endswith('\n'):
yield_line = self.partial_line_
self.partial_line_ = ''
yield yield_line
if partial_line.endswith('\n'):
self.log_history_['partial_line'] = ''
yield partial_line
partial_line = self.log_history_['partial_line']
else:
break
if self.partial_line_:
yield self.partial_line_
if partial_line:
self.log_history_['partial_line'] = ''
yield partial_line
partial_line = self.log_history_['partial_line']
except Exception as error:
logging.error('failed to processing file %s', self.pathname_)
@ -198,22 +124,22 @@ class FileReader(object):
logging.debug(
'processing file %s log %s bytes to position %s',
self.pathname_, self.position_ - old_position,
self.position_)
self.pathname_, position - old_position, position
)
class FileReaderFactory(object):
"""factory class to create FileReader instance."""
def __init__(self, logdir, filefilter):
def __init__(self, logdir):
self.logdir_ = logdir
self.filefilter_ = filefilter
self.filefilter_ = get_file_filter()
def __str__(self):
return '%s[logdir: %s filefilter: %s]' % (
self.__class__.__name__, self.logdir_, self.filefilter_)
def get_file_reader(self, fullname, filename):
def get_file_reader(self, hostname, filename, log_history):
"""Get FileReader instance.
:param fullname: fullname of installing host.
@ -221,17 +147,13 @@ class FileReaderFactory(object):
:returns: :class:`FileReader` instance if it is not filtered.
"""
pathname = os.path.join(self.logdir_, fullname, filename)
pathname = os.path.join(self.logdir_, hostname, filename)
logging.debug('get FileReader from %s', pathname)
if not self.filefilter_.filter(pathname):
logging.error('%s is filtered', pathname)
return None
return FileReader(pathname)
FILE_READER_FACTORY = FileReaderFactory(
setting.INSTALLATION_LOGDIR, get_file_filter())
return FileReader(pathname, log_history)
class FileMatcher(object):
@ -244,71 +166,52 @@ class FileMatcher(object):
self.__class__.__name__,
min_progress,
max_progress))
if 'start' not in line_matchers:
raise KeyError(
'key `start` does not in line matchers %s' % line_matchers
)
self.line_matchers_ = line_matchers
self.min_progress_ = min_progress
self.max_progress_ = max_progress
self.absolute_min_progress_ = 0.0
self.absolute_max_progress_ = 1.0
self.absolute_progress_diff_ = 1.0
self.progress_diff_ = max_progress - min_progress
self.filename_ = filename
def update_absolute_progress_range(self, min_progress, max_progress):
"""update the min progress and max progress the log file indicates."""
progress_diff = max_progress - min_progress
self.absolute_min_progress_ = (
min_progress + self.min_progress_ * progress_diff)
self.absolute_max_progress_ = (
min_progress + self.max_progress_ * progress_diff)
self.absolute_progress_diff_ = (
self.absolute_max_progress_ - self.absolute_min_progress_)
def __str__(self):
return (
'%s[ filename: %s, progress range: [%s:%s], '
'%s[ filename: %s, progress:[%s:%s], '
'line_matchers: %s]' % (
self.__class__.__name__, self.filename_,
self.absolute_min_progress_,
self.absolute_max_progress_, self.line_matchers_)
self.min_progress_,
self.max_progress_, self.line_matchers_)
)
def update_total_progress(self, file_progress, total_progress):
"""Get the total progress from file progress."""
if not file_progress.message:
logging.info(
'ignore update file %s progress %s to total progress',
self.filename_, file_progress)
return
total_progress_data = min(
(
self.absolute_min_progress_ + (
file_progress.progress * self.absolute_progress_diff_
)
),
self.absolute_max_progress_
def update_progress_from_log_history(self, state, log_history):
file_percentage = log_history['percentage']
percentage = max(
self.min_progress_,
min(
self.max_progress_,
self.min_progress_ + file_percentage * self.progress_diff_
)
)
# total progress should only be updated when the new calculated
# progress is greater than the recored total progress or the
# progress to update is the same but the message is different.
if (
total_progress.progress < total_progress_data or (
total_progress.progress == total_progress_data and
total_progress.message != file_progress.message
percentage > state['percentage'] or
(
percentage == state['percentage'] and
log_history['message'] != state['message']
)
):
total_progress.progress = total_progress_data
total_progress.message = file_progress.message
total_progress.severity = file_progress.severity
logging.debug('update file %s total progress %s',
self.filename_, total_progress)
state['percentage'] = percentage
state['message'] = log_history['message']
state['severity'] = log_history['severity']
else:
logging.info(
'ignore update file %s progress %s to total progress %s',
self.filename_, file_progress, total_progress)
logging.debug(
'ingore update state %s from log history %s '
'since the updated progress %s lag behind',
state, log_history, percentage
)
def update_progress(self, fullname, total_progress):
def update_progress(self, file_reader_factory, name, state, log_history):
"""update progress from file.
:param fullname: the fullname of the installing host.
@ -324,23 +227,27 @@ class FileMatcher(object):
run, it will be reprocessed at the beginning because there is
no line end indicator for the last line of the file.
"""
file_reader = FILE_READER_FACTORY.get_file_reader(
fullname, self.filename_)
file_reader = file_reader_factory.get_file_reader(
name, self.filename_, log_history)
if not file_reader:
return
line_matcher_name, file_progress = file_reader.get_history()
line_matcher_name = log_history['line_matcher_name']
for line in file_reader.readline():
if line_matcher_name not in self.line_matchers_:
logging.debug('early exit at\n%s\nbecause %s is not in %s',
line, line_matcher_name, self.line_matchers_)
break
index = line_matcher_name
while index in self.line_matchers_:
line_matcher = self.line_matchers_[index]
index, line_matcher_name = line_matcher.update_progress(
line, file_progress)
file_reader.update_history(line_matcher_name, file_progress)
self.update_total_progress(file_progress, total_progress)
same_line_matcher_name = line_matcher_name
while same_line_matcher_name in self.line_matchers_:
line_matcher = self.line_matchers_[same_line_matcher_name]
same_line_matcher_name, line_matcher_name = (
line_matcher.update_progress(line, log_history)
)
log_history['line_matcher_name'] = line_matcher_name
logging.debug(
'updated log history %s after processing %s',
log_history, self
)
self.update_progress_from_log_history(state, log_history)

View File

@ -21,28 +21,6 @@ from abc import ABCMeta
from compass.utils import util
class Progress(object):
"""Progress object to store installing progress and message."""
def __init__(self, progress, message, severity):
"""Constructor
:param progress: installing progress between 0 to 1.
:param message: installing message.
:param severity: installing message severity.
"""
self.progress = progress
self.message = message
self.severity = severity
def __repr__(self):
return '%s[progress:%s, message:%s, severity:%s]' % (
self.__class__.__name__,
self.progress,
self.message,
self.severity)
class ProgressCalculator(object):
"""base class to generate progress."""
@ -51,7 +29,7 @@ class ProgressCalculator(object):
@classmethod
def update_progress(
cls, progress_data, message,
severity, progress
severity, log_history
):
"""Update progress with the given progress_data, message and severity.
@ -65,24 +43,22 @@ class ProgressCalculator(object):
# is greater than the stored progress or the progress
# to update is the same but the message is different.
if (
progress_data > progress.progress or (
progress_data == progress.progress and
message != progress.message
progress_data > log_history['percentage'] or (
progress_data == log_history['percentage'] and
message != log_history['message']
)
):
progress.progress = progress_data
log_history['percentage'] = progress_data
if message:
progress.message = message
log_history['message'] = message
if severity:
progress.severity = severity
logging.debug('update progress to %s', progress)
log_history['severity'] = severity
logging.debug('update progress to %s', log_history)
else:
logging.info('ignore update progress %s to %s',
progress_data, progress)
progress_data, log_history)
def update(self, message, severity, progress):
def update(self, message, severity, log_history):
"""vritual method to update progress by message and severity.
:param message: installing message.
@ -125,17 +101,17 @@ class IncrementalProgress(ProgressCalculator):
self.incremental_progress_
)
def update(self, message, severity, progress):
def update(self, message, severity, log_history):
"""update progress from message and severity."""
progress_data = max(
self.min_progress_,
min(
self.max_progress_,
progress.progress + self.incremental_progress_
log_history['percentage'] + self.incremental_progress_
)
)
self.update_progress(progress_data,
message, severity, progress)
message, severity, log_history)
class RelativeProgress(ProgressCalculator):
@ -153,19 +129,19 @@ class RelativeProgress(ProgressCalculator):
def __str__(self):
return '%s[%s]' % (self.__class__.__name__, self.progress_)
def update(self, message, severity, progress):
def update(self, message, severity, log_history):
"""update progress from message and severity."""
self.update_progress(
self.progress_, message, severity, progress)
self.progress_, message, severity, log_history)
class SameProgress(ProgressCalculator):
"""class to update message and severity for progress."""
def update(self, message, severity, progress):
def update(self, message, severity, log_history):
"""update progress from the message and severity."""
self.update_progress(progress.progress, message,
severity, progress)
self.update_progress(log_history['percentage'], message,
severity, log_history)
class LineMatcher(object):
@ -201,7 +177,7 @@ class LineMatcher(object):
self.__class__.__name__, self.regex_.pattern,
self.message_template_, self.severity_)
def update_progress(self, line, progress):
def update_progress(self, line, log_history):
"""Update progress by the line.
:param line: one line in log file to indicate the installing progress.
@ -209,7 +185,7 @@ class LineMatcher(object):
The line may be partial if the latest line of the log file is
not the whole line. But the whole line may be resent
in the next run.
:praam progress: the :class:`Progress` instance to update.
:param progress: the :class:`Progress` instance to update.
"""
mat = self.regex_.search(line)
if not mat:
@ -224,7 +200,7 @@ class LineMatcher(object):
self.message_template_, mat.groupdict(), self)
raise error
self.progress_.update(message, self.severity_, progress)
self.progress_.update(message, self.severity_, log_history)
return (
self.match_sameline_,
self.match_nextline_)

View File

@ -19,456 +19,517 @@
import logging
from compass.log_analyzor.adapter_matcher import AdapterItemMatcher
from compass.log_analyzor.adapter_matcher import AdapterMatcher
from compass.log_analyzor.adapter_matcher import OSMatcher
from compass.log_analyzor.adapter_matcher import PackageMatcher
from compass.log_analyzor.file_matcher import FileMatcher
from compass.log_analyzor.file_matcher import FileReaderFactory
from compass.log_analyzor.line_matcher import IncrementalProgress
from compass.log_analyzor.line_matcher import LineMatcher
from compass.utils import setting_wrapper as setting
# TODO(weidong): reconsider intialization method for the following.
OS_INSTALLER_CONFIGURATIONS = {
'Ubuntu': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='syslog',
min_progress=0.0,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=r'.*',
progress=.05,
message_template='start installing',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='ethdetect'
),
'ethdetect': LineMatcher(
pattern=r'Menu.*item.*\'ethdetect\'.*selected',
progress=.1,
message_template='ethdetect selected',
unmatch_nextline_next_matcher_name='ethdetect',
match_nextline_next_matcher_name='netcfg'
),
'netcfg': LineMatcher(
pattern=r'Menu.*item.*\'netcfg\'.*selected',
progress=.12,
message_template='netcfg selected',
unmatch_nextline_next_matcher_name='netcfg',
match_nextline_next_matcher_name='network-preseed'
),
'network-preseed': LineMatcher(
pattern=r'Menu.*item.*\'network-preseed\'.*selected',
progress=.15,
message_template='network-preseed selected',
unmatch_nextline_next_matcher_name='network-preseed',
match_nextline_next_matcher_name='localechooser'
),
'localechoose': LineMatcher(
pattern=r'Menu.*item.*\'localechooser\'.*selected',
progress=.18,
message_template='localechooser selected',
unmatch_nextline_next_matcher_name='localechooser',
match_nextline_next_matcher_name='download-installer'
),
'download-installer': LineMatcher(
pattern=(
r'Menu.*item.*\'download-installer\'.*selected'
'cobbler': {
'Ubuntu': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='syslog',
min_progress=0.0,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=r'.*',
progress=.05,
message_template='start installing',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='ethdetect'
),
progress=.2,
message_template='download installer selected',
unmatch_nextline_next_matcher_name=(
'download-installer'),
match_nextline_next_matcher_name='clock-setup'
),
'clock-setup': LineMatcher(
pattern=r'Menu.*item.*\'clock-setup\'.*selected',
progress=.3,
message_template='clock-setup selected',
unmatch_nextline_next_matcher_name='clock-setup',
match_nextline_next_matcher_name='disk-detect'
),
'disk-detect': LineMatcher(
pattern=r'Menu.*item.*\'disk-detect\'.*selected',
progress=.32,
message_template='disk-detect selected',
unmatch_nextline_next_matcher_name='disk-detect',
match_nextline_next_matcher_name='partman-base'
),
'partman-base': LineMatcher(
pattern=r'Menu.*item.*\'partman-base\'.*selected',
progress=.35,
message_template='partman-base selected',
unmatch_nextline_next_matcher_name='partman-base',
match_nextline_next_matcher_name='live-installer'
),
'live-installer': LineMatcher(
pattern=r'Menu.*item.*\'live-installer\'.*selected',
progress=.45,
message_template='live-installer selected',
unmatch_nextline_next_matcher_name='live-installer',
match_nextline_next_matcher_name='pkgsel'
),
'pkgsel': LineMatcher(
pattern=r'Menu.*item.*\'pkgsel\'.*selected',
progress=.5,
message_template='pkgsel selected',
unmatch_nextline_next_matcher_name='pkgsel',
match_nextline_next_matcher_name='grub-installer'
),
'grub-installer': LineMatcher(
pattern=r'Menu.*item.*\'grub-installer\'.*selected',
progress=.9,
message_template='grub-installer selected',
unmatch_nextline_next_matcher_name='grub-installer',
match_nextline_next_matcher_name='finish-install'
),
'finish-install': LineMatcher(
pattern=r'Menu.*item.*\'finish-install\'.*selected',
progress=.95,
message_template='finish-install selected',
unmatch_nextline_next_matcher_name='finish-install',
match_nextline_next_matcher_name='finish-install-done'
),
'finish-install-done': LineMatcher(
pattern=r'Running.*finish-install.d/.*save-logs',
progress=1.0,
message_template='finish-install is done',
unmatch_nextline_next_matcher_name=(
'finish-install-done'
'ethdetect': LineMatcher(
pattern=r'Menu.*item.*\'ethdetect\'.*selected',
progress=.1,
message_template='ethdetect selected',
unmatch_nextline_next_matcher_name='ethdetect',
match_nextline_next_matcher_name='netcfg'
),
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='status',
min_progress=.2,
max_progress=.3,
line_matchers={
'start': LineMatcher(
pattern=r'Package: (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.05),
message_template='Installing udeb %(package)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
)
}
),
FileMatcher(
filename='initial-status',
min_progress=.5,
max_progress=.9,
line_matchers={
'start': LineMatcher(
pattern=r'Package: (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.01),
message_template='Installing deb %(package)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
)
}
),
]
),
'CentOS': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='sys.log',
min_progress=0.0,
max_progress=0.1,
line_matchers={
'start': LineMatcher(
pattern=r'NOTICE (?P<message>.*)',
progress=IncrementalProgress(.1, .9, .1),
message_template='%(message)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='anaconda.log',
min_progress=0.1,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=r'setting.*up.*kickstart',
progress=.1,
message_template=(
'Setting up kickstart configurations'),
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='STEP_STAGE2'
),
'STEP_STAGE2': LineMatcher(
pattern=r'starting.*STEP_STAGE2',
progress=.15,
message_template=(
'Downloading installation '
'images from server'),
unmatch_nextline_next_matcher_name='STEP_STAGE2',
match_nextline_next_matcher_name='start_anaconda'
),
'start_anaconda': LineMatcher(
pattern=r'Running.*anaconda.*script',
progress=.2,
unmatch_nextline_next_matcher_name=(
'start_anaconda'),
match_nextline_next_matcher_name=(
'start_kickstart_pre')
),
'start_kickstart_pre': LineMatcher(
pattern=r'Running.*kickstart.*pre.*script',
progress=.25,
unmatch_nextline_next_matcher_name=(
'start_kickstart_pre'),
match_nextline_next_matcher_name=(
'kickstart_pre_done')
),
'kickstart_pre_done': LineMatcher(
pattern=(
r'All.*kickstart.*pre.*script.*have.*been.*run'),
progress=.3,
unmatch_nextline_next_matcher_name=(
'kickstart_pre_done'),
match_nextline_next_matcher_name=(
'start_enablefilesystem')
),
'start_enablefilesystem': LineMatcher(
pattern=r'moving.*step.*enablefilesystems',
progress=0.3,
message_template=(
'Performing hard-disk partitioning and '
'enabling filesystems'),
unmatch_nextline_next_matcher_name=(
'start_enablefilesystem'),
match_nextline_next_matcher_name=(
'enablefilesystem_done')
),
'enablefilesystem_done': LineMatcher(
pattern=r'leaving.*step.*enablefilesystems',
progress=.35,
message_template='Filesystems are enabled',
unmatch_nextline_next_matcher_name=(
'enablefilesystem_done'),
match_nextline_next_matcher_name=(
'setup_repositories')
),
'setup_repositories': LineMatcher(
pattern=r'moving.*step.*reposetup',
progress=0.35,
message_template=(
'Setting up Customized Repositories'),
unmatch_nextline_next_matcher_name=(
'setup_repositories'),
match_nextline_next_matcher_name=(
'repositories_ready')
),
'repositories_ready': LineMatcher(
pattern=r'leaving.*step.*reposetup',
progress=0.4,
message_template=(
'Customized Repositories setting up are done'),
unmatch_nextline_next_matcher_name=(
'repositories_ready'),
match_nextline_next_matcher_name='checking_dud'
),
'checking_dud': LineMatcher(
pattern=r'moving.*step.*postselection',
progress=0.4,
message_template='Checking DUD modules',
unmatch_nextline_next_matcher_name='checking_dud',
match_nextline_next_matcher_name='dud_checked'
),
'dud_checked': LineMatcher(
pattern=r'leaving.*step.*postselection',
progress=0.5,
message_template='Checking DUD modules are done',
unmatch_nextline_next_matcher_name='dud_checked',
match_nextline_next_matcher_name='installing_packages'
),
'installing_packages': LineMatcher(
pattern=r'moving.*step.*installpackages',
progress=0.5,
message_template='Installing packages',
unmatch_nextline_next_matcher_name=(
'installing_packages'),
match_nextline_next_matcher_name=(
'packages_installed')
),
'packages_installed': LineMatcher(
pattern=r'leaving.*step.*installpackages',
progress=0.8,
message_template='Packages are installed',
unmatch_nextline_next_matcher_name=(
'packages_installed'),
match_nextline_next_matcher_name=(
'installing_bootloader')
),
'installing_bootloader': LineMatcher(
pattern=r'moving.*step.*instbootloader',
progress=0.9,
message_template='Installing bootloaders',
unmatch_nextline_next_matcher_name=(
'installing_bootloader'),
match_nextline_next_matcher_name=(
'bootloader_installed'),
),
'bootloader_installed': LineMatcher(
pattern=r'leaving.*step.*instbootloader',
progress=1.0,
message_template='bootloaders is installed',
unmatch_nextline_next_matcher_name=(
'bootloader_installed'),
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='install.log',
min_progress=0.56,
max_progress=0.80,
line_matchers={
'start': LineMatcher(
pattern=r'Installing (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.005),
message_template='Installing %(package)s',
unmatch_sameline_next_matcher_name='package_complete',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
),
'package_complete': LineMatcher(
pattern='FINISHED.*INSTALLING.*PACKAGES',
progress=1.0,
message_template='installing packages finished',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
]
),
'netcfg': LineMatcher(
pattern=r'Menu.*item.*\'netcfg\'.*selected',
progress=.12,
message_template='netcfg selected',
unmatch_nextline_next_matcher_name='netcfg',
match_nextline_next_matcher_name='network-preseed'
),
'network-preseed': LineMatcher(
pattern=(
r'Menu.*item.*\'network-preseed\'.*selected'
),
progress=.15,
message_template='network-preseed selected',
unmatch_nextline_next_matcher_name=(
'network-preseed'
),
match_nextline_next_matcher_name='localechooser'
),
'localechoose': LineMatcher(
pattern=r'Menu.*item.*\'localechooser\'.*selected',
progress=.18,
message_template='localechooser selected',
unmatch_nextline_next_matcher_name='localechooser',
match_nextline_next_matcher_name=(
'download-installer'
)
),
'download-installer': LineMatcher(
pattern=(
r'Menu.*item.*\'download-installer\'.*selected'
),
progress=.2,
message_template='download installer selected',
unmatch_nextline_next_matcher_name=(
'download-installer'),
match_nextline_next_matcher_name='clock-setup'
),
'clock-setup': LineMatcher(
pattern=r'Menu.*item.*\'clock-setup\'.*selected',
progress=.3,
message_template='clock-setup selected',
unmatch_nextline_next_matcher_name='clock-setup',
match_nextline_next_matcher_name='disk-detect'
),
'disk-detect': LineMatcher(
pattern=r'Menu.*item.*\'disk-detect\'.*selected',
progress=.32,
message_template='disk-detect selected',
unmatch_nextline_next_matcher_name='disk-detect',
match_nextline_next_matcher_name='partman-base'
),
'partman-base': LineMatcher(
pattern=(
r'Menu.*item.*\'partman-base\'.*selected'
),
progress=.35,
message_template='partman-base selected',
unmatch_nextline_next_matcher_name='partman-base',
match_nextline_next_matcher_name='live-installer'
),
'live-installer': LineMatcher(
pattern=(
r'Menu.*item.*\'live-installer\'.*selected'
),
progress=.45,
message_template='live-installer selected',
unmatch_nextline_next_matcher_name=(
'live-installer'
),
match_nextline_next_matcher_name='pkgsel'
),
'pkgsel': LineMatcher(
pattern=r'Menu.*item.*\'pkgsel\'.*selected',
progress=.5,
message_template='pkgsel selected',
unmatch_nextline_next_matcher_name='pkgsel',
match_nextline_next_matcher_name='grub-installer'
),
'grub-installer': LineMatcher(
pattern=(
r'Menu.*item.*\'grub-installer\'.*selected'
),
progress=.9,
message_template='grub-installer selected',
unmatch_nextline_next_matcher_name=(
'grub-installer'
),
match_nextline_next_matcher_name='finish-install'
),
'finish-install': LineMatcher(
pattern=(
r'Menu.*item.*\'finish-install\'.*selected'
),
progress=.95,
message_template='finish-install selected',
unmatch_nextline_next_matcher_name=(
'finish-install'
),
match_nextline_next_matcher_name=(
'finish-install-done'
)
),
'finish-install-done': LineMatcher(
pattern=(
r'Running.*finish-install.d/.*save-logs'
),
progress=1.0,
message_template='finish-install is done',
unmatch_nextline_next_matcher_name=(
'finish-install-done'
),
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='status',
min_progress=.2,
max_progress=.3,
line_matchers={
'start': LineMatcher(
pattern=r'Package: (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.05),
message_template='Installing udeb %(package)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
)
}
),
FileMatcher(
filename='initial-status',
min_progress=.5,
max_progress=.9,
line_matchers={
'start': LineMatcher(
pattern=r'Package: (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.01),
message_template='Installing deb %(package)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
)
}
),
]
),
'CentOS': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='sys.log',
min_progress=0.0,
max_progress=0.1,
line_matchers={
'start': LineMatcher(
pattern=r'NOTICE (?P<message>.*)',
progress=IncrementalProgress(.1, .9, .1),
message_template='%(message)s',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='anaconda.log',
min_progress=0.1,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=r'setting.*up.*kickstart',
progress=.1,
message_template=(
'Setting up kickstart configurations'),
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='STEP_STAGE2'
),
'STEP_STAGE2': LineMatcher(
pattern=r'starting.*STEP_STAGE2',
progress=.15,
message_template=(
'Downloading installation '
'images from server'),
unmatch_nextline_next_matcher_name='STEP_STAGE2',
match_nextline_next_matcher_name='start_anaconda'
),
'start_anaconda': LineMatcher(
pattern=r'Running.*anaconda.*script',
progress=.2,
unmatch_nextline_next_matcher_name=(
'start_anaconda'),
match_nextline_next_matcher_name=(
'start_kickstart_pre')
),
'start_kickstart_pre': LineMatcher(
pattern=r'Running.*kickstart.*pre.*script',
progress=.25,
unmatch_nextline_next_matcher_name=(
'start_kickstart_pre'),
match_nextline_next_matcher_name=(
'kickstart_pre_done')
),
'kickstart_pre_done': LineMatcher(
pattern=(
r'All.*kickstart.*pre'
'.*script.*have.*been.*run'
),
progress=.3,
unmatch_nextline_next_matcher_name=(
'kickstart_pre_done'),
match_nextline_next_matcher_name=(
'start_enablefilesystem')
),
'start_enablefilesystem': LineMatcher(
pattern=(
r'moving.*step.*enablefilesystems'
),
progress=0.3,
message_template=(
'Performing hard-disk partitioning and '
'enabling filesystems'
),
unmatch_nextline_next_matcher_name=(
'start_enablefilesystem'),
match_nextline_next_matcher_name=(
'enablefilesystem_done')
),
'enablefilesystem_done': LineMatcher(
pattern=(
r'leaving.*step.*enablefilesystems'
),
progress=.35,
message_template='Filesystems are enabled',
unmatch_nextline_next_matcher_name=(
'enablefilesystem_done'),
match_nextline_next_matcher_name=(
'setup_repositories')
),
'setup_repositories': LineMatcher(
pattern=r'moving.*step.*reposetup',
progress=0.35,
message_template=(
'Setting up Customized Repositories'
),
unmatch_nextline_next_matcher_name=(
'setup_repositories'),
match_nextline_next_matcher_name=(
'repositories_ready')
),
'repositories_ready': LineMatcher(
pattern=r'leaving.*step.*reposetup',
progress=0.4,
message_template=(
'Customized Repositories setting up are done'
),
unmatch_nextline_next_matcher_name=(
'repositories_ready'),
match_nextline_next_matcher_name='checking_dud'
),
'checking_dud': LineMatcher(
pattern=r'moving.*step.*postselection',
progress=0.4,
message_template='Checking DUD modules',
unmatch_nextline_next_matcher_name='checking_dud',
match_nextline_next_matcher_name='dud_checked'
),
'dud_checked': LineMatcher(
pattern=r'leaving.*step.*postselection',
progress=0.5,
message_template='Checking DUD modules are done',
unmatch_nextline_next_matcher_name='dud_checked',
match_nextline_next_matcher_name=(
'installing_packages'
)
),
'installing_packages': LineMatcher(
pattern=r'moving.*step.*installpackages',
progress=0.5,
message_template='Installing packages',
unmatch_nextline_next_matcher_name=(
'installing_packages'),
match_nextline_next_matcher_name=(
'packages_installed')
),
'packages_installed': LineMatcher(
pattern=r'leaving.*step.*installpackages',
progress=0.8,
message_template='Packages are installed',
unmatch_nextline_next_matcher_name=(
'packages_installed'),
match_nextline_next_matcher_name=(
'installing_bootloader')
),
'installing_bootloader': LineMatcher(
pattern=r'moving.*step.*instbootloader',
progress=0.9,
message_template='Installing bootloaders',
unmatch_nextline_next_matcher_name=(
'installing_bootloader'),
match_nextline_next_matcher_name=(
'bootloader_installed'),
),
'bootloader_installed': LineMatcher(
pattern=r'leaving.*step.*instbootloader',
progress=1.0,
message_template='bootloaders is installed',
unmatch_nextline_next_matcher_name=(
'bootloader_installed'),
match_nextline_next_matcher_name='exit'
),
}
),
FileMatcher(
filename='install.log',
min_progress=0.56,
max_progress=0.80,
line_matchers={
'start': LineMatcher(
pattern=r'Installing (?P<package>.*)',
progress=IncrementalProgress(0.0, 0.99, 0.005),
message_template='Installing %(package)s',
unmatch_sameline_next_matcher_name=(
'package_complete'
),
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
),
'package_complete': LineMatcher(
pattern='FINISHED.*INSTALLING.*PACKAGES',
progress=1.0,
message_template='installing packages finished',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
]
),
}
}
PACKAGE_INSTALLER_CONFIGURATIONS = {
'openstack': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='chef-client.log',
min_progress=0.1,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=(
r'Processing\s*(?P<install_type>.*)'
r'\[(?P<package>.*)\].*'),
progress=IncrementalProgress(0.0, .90, 0.005),
message_template=(
'Processing %(install_type)s %(package)s'),
unmatch_sameline_next_matcher_name=(
'chef_complete'),
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
),
'chef_complete': LineMatcher(
pattern=r'Chef.*Run.*complete',
progress=1.0,
message_template='Chef run complete',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
]
),
'chef_installer': {
'openstack': AdapterItemMatcher(
file_matchers=[
FileMatcher(
filename='chef-client.log',
min_progress=0.1,
max_progress=1.0,
line_matchers={
'start': LineMatcher(
pattern=(
r'Processing\s*(?P<install_type>.*)'
r'\[(?P<package>.*)\].*'),
progress=IncrementalProgress(0.0, .90, 0.005),
message_template=(
'Processing %(install_type)s %(package)s'),
unmatch_sameline_next_matcher_name=(
'chef_complete'),
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='start'
),
'chef_complete': LineMatcher(
pattern=r'Chef.*Run.*complete',
progress=1.0,
message_template='Chef run complete',
unmatch_nextline_next_matcher_name='start',
match_nextline_next_matcher_name='exit'
),
}
),
]
),
}
}
OS_ADAPTER_CONFIGURATIONS = [
OSMatcher(
os_installer_name='cobbler',
os_pattern='CentOS.*',
item_matcher=OS_INSTALLER_CONFIGURATIONS['CentOS'],
min_progress=0.0,
max_progress=1.0
item_matcher=OS_INSTALLER_CONFIGURATIONS['cobbler']['CentOS'],
file_reader_factory=FileReaderFactory(
setting.INSTALLATION_LOGDIR['CobblerInstaller']
)
),
OSMatcher(
os_installer_name='cobbler',
os_pattern='Ubuntu.*',
item_matcher=OS_INSTALLER_CONFIGURATIONS['Ubuntu'],
min_progress=0.0,
max_progress=1.0
item_matcher=OS_INSTALLER_CONFIGURATIONS['cobbler']['Ubuntu'],
file_reader_factory=FileReaderFactory(
setting.INSTALLATION_LOGDIR['CobblerInstaller']
)
)
]
PACKAGE_ADAPTER_CONFIGURATIONS = [
PackageMatcher(
package_installer_name='chef.*',
target_system='openstack',
item_matcher=PACKAGE_INSTALLER_CONFIGURATIONS['openstack'],
min_progress=0.0,
max_progress=1.0
package_installer_name='chef_installer',
distributed_system_pattern='openstack.*',
item_matcher=PACKAGE_INSTALLER_CONFIGURATIONS[
'chef_installer']['openstack'],
file_reader_factory=FileReaderFactory(
setting.INSTALLATION_LOGDIR['ChefInstaller']
)
)
]
def _get_os_adapter_matcher(os_installer, os_name):
def _get_os_matcher(os_installer_name, os_name):
"""Get OS adapter matcher by os name and installer name."""
for configuration in OS_ADAPTER_CONFIGURATIONS:
if configuration.match(os_installer, os_name):
if configuration.match(os_installer_name, os_name):
return configuration
else:
logging.debug('configuration %s does not match %s and %s',
configuration, os_name, os_installer)
configuration, os_name, os_installer_name)
logging.error('No configuration found for os installer %s os %s',
os_installer, os_name)
os_installer_name, os_name)
return None
def _get_package_adapter_matcher(package_installer, target_system):
def _get_package_matcher(
package_installer_name, distributed_system_name
):
"""Get package adapter matcher by pacakge name and installer name."""
for configuration in PACKAGE_ADAPTER_CONFIGURATIONS:
if configuration.match(package_installer, target_system):
if configuration.match(
package_installer_name,
distributed_system_name
):
return configuration
else:
logging.debug('configuration %s does not match %s and %s',
configuration, target_system, package_installer)
configuration, distributed_system_name,
package_installer_name)
logging.error('No configuration found for package installer %s os %s',
package_installer, target_system)
package_installer_name, distributed_system_name)
return None
def update_progress(
os_installers, os_names, package_installers, target_systems,
cluster_hosts
):
"""Update adapter installing progress.
:param os_installers: cluster id to os installer name
:param package_installers: cluster id to package installer name.
:param cluster_hosts: clusters and hosts in each cluster to update.
:param cluster_hosts: dict of int to list of int.
"""
for clusterid, hostids in cluster_hosts.items():
"""
adapter = _get_adapter_matcher(os_installers[clusterid],
os_names[clusterid],
package_installers[clusterid],
target_systems[clusterid])
if not adapter:
continue
adapter.update_progress(clusterid, hostids)
"""
os_adapter = _get_os_adapter_matcher(
os_installers[clusterid], os_names[clusterid]
def update_host_progress(host_mappping):
for host_id, (host, host_state, host_log_history_mapping) in (
host_mappping.items()
):
os_name = host['os_name']
os_installer_name = host['os_installer']['name']
os_matcher = _get_os_matcher(
os_installer_name, os_name
)
package_adapter = _get_package_adapter_matcher(
package_installers[clusterid],
target_systems[clusterid]
)
if not (os_adapter or package_adapter):
if not os_matcher:
continue
name = host[setting.HOST_INSTALLATION_LOGDIR_NAME]
os_matcher.update_progress(
name, host_state, host_log_history_mapping
)
adapter = AdapterMatcher(os_adapter, package_adapter)
adapter.update_progress(clusterid, hostids)
def update_clusterhost_progress(clusterhost_mapping):
for (
clusterhost_id,
(clusterhost, clusterhost_state, clusterhost_log_history_mapping)
) in (
clusterhost_mapping.items()
):
distributed_system_name = clusterhost['distributed_system_name']
package_installer_name = clusterhost['package_installer']['name']
package_matcher = _get_package_matcher(
package_installer_name,
distributed_system_name
)
if not package_matcher:
continue
name = clusterhost[setting.CLUSTERHOST_INATALLATION_LOGDIR_NAME]
package_matcher.update_progress(
name, clusterhost_state,
clusterhost_log_history_mapping
)
def update_cluster_progress(cluster_mapping):
for cluster_id, (cluster, cluster_state) in cluster_mapping.items():
pass

View File

@ -104,9 +104,6 @@ def reinstall_cluster(installer_email, cluster_id, clusterhost_ids):
@celery.task(name='compass.tasks.poweron_host')
def poweron_host(host_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@ -114,9 +111,6 @@ def poweron_host(host_id):
@celery.task(name='compass.tasks.poweroff_host')
def poweroff_host(host_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@ -124,9 +118,6 @@ def poweroff_host(host_id):
@celery.task(name='compass.tasks.reset_host')
def reset_host(host_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@ -134,9 +125,6 @@ def reset_host(host_id):
@celery.task(name='compass.tasks.poweron_machine')
def poweron_machine(machine_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@ -144,9 +132,6 @@ def poweron_machine(machine_id):
@celery.task(name='compass.tasks.poweroff_machine')
def poweroff_machine(machine_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@ -154,22 +139,16 @@ def poweroff_machine(machine_id):
@celery.task(name='compass.tasks.reset_machine')
def reset_machine(machine_id):
"""Deploy the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to deploy.
:type cluster_hosts: dict of int to list of int
"""
pass
@celery.task(name='compass.tasks.update_progress')
def update_clusters_progress(cluster_hosts):
def update_clusters_progress():
"""Calculate the installing progress of the given cluster.
:param cluster_hosts: the cluster and hosts of each cluster to update.
:type cluster_hosts: dict of int to list of int
"""
logging.info('update_clusters_progress: %s', cluster_hosts)
logging.info('update_clusters_progress')
try:
update_progress.update_progress(cluster_hosts)
update_progress.update_progress()
except Exception as error:
logging.exception(error)

View File

@ -563,12 +563,12 @@ class TestUpdateDbObject(unittest2.TestCase):
db_obj = utils.get_db_object(
session,
models.Permission,
id=1
id=1000
)
utils.updated_db_object(
utils.update_db_object(
session,
db_obj,
dummy='dummy'
name='dummy'
)

View File

@ -28,8 +28,10 @@ CONFIG_DIR = '/etc/compass'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
INSTALLATION_LOGDIR = {
'CobblerInstaller': '/var/log/cobbler/anamon',
'ChefInstaller': '/var/log/chef'
'ChefInstaller': '/var/log/cobbler/anamon'
}
CLUSTERHOST_INATALLATION_LOGDIR_NAME = 'hostname'
HOST_INSTALLATION_LOGDIR_NAME = 'hostname'
DEFAULT_LOGLEVEL = 'debug'
DEFAULT_LOGDIR = '/tmp'
DEFAULT_LOGINTERVAL = 1

View File

@ -1,9 +1,9 @@
NAME = 'chef_installer'
INSTANCE_NAME = 'chef_installer'
SETTINGS = {
'chef_url': 'https://$chef_host',
'chef_server_ip': '',
'chef_server_dns': '',
'chef_url': 'https://$chef_ip',
'chef_server_ip': '$chef_ip',
'chef_server_dns': '$chef_hostname',
'key_dir': '',
'client_name': '',
'databags': ['user_passwords', 'db_passwords', 'service_passwords', 'secrets']

View File

@ -7,7 +7,7 @@ DATABASE_NAME = 'db'
SQLALCHEMY_DATABASE_URI = '%s://%s:%s@%s/%s' % (DATABASE_TYPE, DATABASE_USER, DATABASE_PASSWORD, DATABASE_SERVER, DATABASE_NAME)
INSTALLATION_LOGDIR = {
'CobblerInstaller': '/var/log/cobbler/anamon',
'ChefInstaller': '/var/log/chef'
'ChefInstaller': '/var/log/cobbler/anamon'
}
DEFAULT_LOGLEVEL = 'debug'
DEFAULT_LOGDIR = '/var/log/compass'

View File

@ -47,6 +47,7 @@ sudo sed -i "/COBBLER_INSTALLER_URL/c\COBBLER_INSTALLER_URL = 'http:\/\/$ipaddr/
sudo sed -i "s/\$cobbler_ip/$ipaddr/g" /etc/compass/os_installer/cobbler.conf
sudo sed -i "/CHEF_INSTALLER_URL/c\CHEF_INSTALLER_URL = 'https:\/\/$ipaddr/'" /etc/compass/setting
sudo sed -i "s/\$chef_ip/$ipaddr/g" /etc/compass/package_installer/chef-icehouse.conf
sudo sed -i "s/\$chef_hostname/$HOSTNAME/g" /etc/compass/package_installer/chef-icehouse.conf
sudo sed -i "s/\$compass_ip/$ipaddr/g" /etc/compass/global_config
sudo sed -i "s/\$compass_hostname/$HOSTNAME/g" /etc/compass/global_config
sudo sed -i "s/\$compass_testmode/$TESTMODE/g" /etc/compass/global_config