update log analyzor code and fix some api bug.
Change-Id: I1247cd89e4dc44559016451e509e55f0541de480
This commit is contained in:
parent
c80a75a3ed
commit
28451394e4
@ -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+'),
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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_)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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']
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user