diff options
Diffstat (limited to 'compass-deck/db/api/host.py')
-rw-r--r-- | compass-deck/db/api/host.py | 1120 |
1 files changed, 1120 insertions, 0 deletions
diff --git a/compass-deck/db/api/host.py b/compass-deck/db/api/host.py new file mode 100644 index 0000000..15e0bb6 --- /dev/null +++ b/compass-deck/db/api/host.py @@ -0,0 +1,1120 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Host database operations.""" +import functools +import logging +import netaddr +import re + +from compass.db.api import database +from compass.db.api import metadata_holder as metadata_api +from compass.db.api import permission +from compass.db.api import user as user_api +from compass.db.api import utils +from compass.db import exception +from compass.db import models +from compass.utils import util + + +SUPPORTED_FIELDS = ['name', 'os_name', 'owner', 'mac', 'id'] +SUPPORTED_MACHINE_HOST_FIELDS = [ + 'mac', 'tag', 'location', 'os_name', 'os_id' +] +SUPPORTED_NETOWORK_FIELDS = [ + 'interface', 'ip', 'is_mgmt', 'is_promiscuous' +] +RESP_FIELDS = [ + 'id', 'name', 'hostname', 'os_name', 'owner', 'mac', + 'switch_ip', 'port', 'switches', 'os_installer', 'os_id', 'ip', + 'reinstall_os', 'os_installed', 'tag', 'location', 'networks', + 'created_at', 'updated_at' +] +RESP_CLUSTER_FIELDS = [ + 'id', 'name', 'os_name', 'reinstall_distributed_system', + 'owner', 'adapter_name', 'flavor_name', + 'distributed_system_installed', 'created_at', 'updated_at' +] +RESP_NETWORK_FIELDS = [ + 'id', 'ip', 'interface', 'netmask', 'is_mgmt', 'is_promiscuous', + 'created_at', 'updated_at' +] +RESP_CONFIG_FIELDS = [ + 'os_config', + 'config_setp', + 'config_validated', + 'networks', + 'created_at', + 'updated_at' +] +RESP_DEPLOYED_CONFIG_FIELDS = [ + 'deployed_os_config' +] +RESP_DEPLOY_FIELDS = [ + 'status', 'host' +] +UPDATED_FIELDS = ['name', 'reinstall_os'] +UPDATED_CONFIG_FIELDS = [ + 'put_os_config' +] +PATCHED_CONFIG_FIELDS = [ + 'patched_os_config' +] +UPDATED_DEPLOYED_CONFIG_FIELDS = [ + 'deployed_os_config' +] +ADDED_NETWORK_FIELDS = [ + 'interface', 'ip', 'subnet_id' +] +OPTIONAL_ADDED_NETWORK_FIELDS = ['is_mgmt', 'is_promiscuous'] +UPDATED_NETWORK_FIELDS = [ + 'interface', 'ip', 'subnet_id', 'subnet', 'is_mgmt', + 'is_promiscuous' +] +IGNORE_FIELDS = [ + 'id', 'created_at', 'updated_at' +] +RESP_STATE_FIELDS = [ + 'id', 'state', 'percentage', 'message', 'severity', 'ready' +] +UPDATED_STATE_FIELDS = [ + 'state', 'percentage', 'message', 'severity' +] +UPDATED_STATE_INTERNAL_FIELDS = [ + 'ready' +] +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' +] + + +@utils.supported_filters(optional_support_keys=SUPPORTED_FIELDS) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOSTS +) +@utils.wrap_to_dict(RESP_FIELDS) +def list_hosts(user=None, session=None, **filters): + """List hosts.""" + return utils.list_db_objects( + session, models.Host, **filters + ) + + +@utils.supported_filters( + optional_support_keys=SUPPORTED_MACHINE_HOST_FIELDS) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOSTS +) +@utils.output_filters( + missing_ok=True, + tag=utils.general_filter_callback, + location=utils.general_filter_callback, + os_name=utils.general_filter_callback, + os_id=utils.general_filter_callback +) +@utils.wrap_to_dict(RESP_FIELDS) +def list_machines_or_hosts(user=None, session=None, **filters): + """List machines or hosts if possible.""" + machines = utils.list_db_objects( + session, models.Machine, **filters + ) + machines_or_hosts = [] + for machine in machines: + host = machine.host + if host: + machines_or_hosts.append(host) + else: + machines_or_hosts.append(machine) + return machines_or_hosts + + +def _get_host(host_id, session=None, **kwargs): + """Get host by id.""" + if isinstance(host_id, (int, long)): + return utils.get_db_object( + session, models.Host, + id=host_id, **kwargs + ) + else: + raise exception.InvalidParameter( + 'host id %s type is not int compatible' % host_id + ) + + +def get_host_internal(host_id, session=None, **kwargs): + """Helper function to get host. + + Used by other files under db/api. + """ + return _get_host(host_id, session=session, **kwargs) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOSTS +) +@utils.wrap_to_dict(RESP_FIELDS) +def get_host( + host_id, exception_when_missing=True, + user=None, session=None, **kwargs +): + """get host info.""" + return _get_host( + host_id, + exception_when_missing=exception_when_missing, + session=session + ) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOSTS +) +@utils.wrap_to_dict(RESP_FIELDS) +def get_machine_or_host( + host_id, exception_when_missing=True, + user=None, session=None, **kwargs +): + """get machine or host if possible.""" + from compass.db.api import machine as machine_api + machine = machine_api.get_machine_internal( + host_id, + exception_when_missing=exception_when_missing, + session=session + ) + if machine.host: + return machine.host + else: + return machine + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_CLUSTERS +) +@utils.wrap_to_dict(RESP_CLUSTER_FIELDS) +def get_host_clusters(host_id, user=None, session=None, **kwargs): + """get host clusters.""" + host = _get_host(host_id, session=session) + return [clusterhost.cluster for clusterhost in host.clusterhosts] + + +def check_host_validated(host): + """Check host is validated.""" + if not host.config_validated: + raise exception.Forbidden( + 'host %s is not validated' % host.name + ) + + +def check_host_editable( + host, user=None, + check_in_installing=False +): + """Check host is editable. + + If we try to set reinstall_os or check the host is not in installing + state, we should set check_in_installing to True. + Otherwise we will check the host is not in installing or installed. + We also make sure the user is admin or the owner of the host to avoid + unauthorized user to update host attributes. + """ + if check_in_installing: + if host.state.state == 'INSTALLING': + raise exception.Forbidden( + 'host %s is not editable ' + 'when state is in installing' % host.name + ) + elif not host.reinstall_os: + raise exception.Forbidden( + 'host %s is not editable ' + 'when not to be reinstalled' % host.name + ) + if user and not user.is_admin and host.creator_id != user.id: + raise exception.Forbidden( + 'host %s is not editable ' + 'when user is not admin or the owner of the host' % host.name + ) + + +def is_host_editable( + host, user=None, + check_in_installing=False +): + """Get if host is editable.""" + try: + check_host_editable( + host, user=user, + check_in_installing=check_in_installing + ) + return True + except exception.Forbidden: + return False + + +def validate_host(host): + """Validate host. + + Makesure hostname is not empty, there is only one mgmt network, + The mgmt network is not in promiscuous mode. + """ + if not host.hostname: + raise exception.Invalidparameter( + 'host %s does not set hostname' % host.name + ) + if not host.host_networks: + raise exception.InvalidParameter( + 'host %s does not have any network' % host.name + ) + mgmt_interface_set = False + for host_network in host.host_networks: + if host_network.is_mgmt: + if mgmt_interface_set: + raise exception.InvalidParameter( + 'host %s multi interfaces set mgmt ' % host.name + ) + if host_network.is_promiscuous: + raise exception.InvalidParameter( + 'host %s interface %s is mgmt but promiscuous' % ( + host.name, host_network.interface + ) + ) + mgmt_interface_set = True + if not mgmt_interface_set: + raise exception.InvalidParameter( + 'host %s has no mgmt interface' % host.name + ) + + +@utils.supported_filters( + optional_support_keys=UPDATED_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@utils.input_validates(name=utils.check_name) +@utils.wrap_to_dict(RESP_FIELDS) +def _update_host(host_id, session=None, user=None, **kwargs): + """Update a host internal.""" + host = _get_host(host_id, session=session) + if host.state.state == "SUCCESSFUL" and not host.reinstall_os: + logging.info("ignoring successful host: %s", host_id) + return {} + check_host_editable( + host, user=user, + check_in_installing=kwargs.get('reinstall_os', False) + ) + return utils.update_db_object(session, host, **kwargs) + + +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_UPDATE_HOST +) +def update_host(host_id, user=None, session=None, **kwargs): + """Update a host.""" + return _update_host(host_id, session=session, user=user, **kwargs) + + +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_UPDATE_HOST +) +def update_hosts(data=[], user=None, session=None): + """Update hosts.""" + # TODO(xicheng): this batch function is not similar as others. + # try to make it similar output as others and batch update should + # tolerate partial failure. + hosts = [] + for host_data in data: + hosts.append(_update_host(session=session, user=user, **host_data)) + return hosts + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEL_HOST +) +@utils.wrap_to_dict( + RESP_FIELDS + ['status', 'host'], + host=RESP_FIELDS +) +def del_host( + host_id, force=False, from_database_only=False, + user=None, session=None, **kwargs +): + """Delete a host. + + If force, we delete the host anyway. + If from_database_only, we only delete the host record in databaes. + Otherwise we send to del host task to celery to delete the host + record in os installer and package installer, clean installation logs + and at last clean database record. + The backend will call this function again after it deletes the record + in os installer and package installer with from_database_only set. + """ + from compass.db.api import cluster as cluster_api + host = _get_host(host_id, session=session) + # force set host state to ERROR when we want to delete the + # host anyway even the host is in installing or already + # installed. It let the api know the deleting is in doing when backend + # is doing the real deleting. In future we may import a new state like + # INDELETE to indicate the deleting is processing. + # We need discuss about if we can delete a host when it is already + # installed by api. + if host.state.state != 'UNINITIALIZED' and force: + host.state.state = 'ERROR' + check_host_editable( + host, user=user, + check_in_installing=True + ) + cluster_ids = [] + for clusterhost in host.clusterhosts: + if clusterhost.state.state != 'UNINITIALIZED' and force: + clusterhost.state.state = 'ERROR' + # TODO(grace): here we check all clusters which use this host editable. + # Because in backend we do not have functions to delete host without + # reference its cluster. After deleting pure host supported in backend, + # we should change code here to is_cluster_editable. + # Here delete a host may fail even we set force flag. + cluster_api.check_cluster_editable( + clusterhost.cluster, user=user, + check_in_installing=True + ) + cluster_ids.append(clusterhost.cluster_id) + + # Delete host record directly if there is no need to delete it + # in backend or from_database_only is set. + if host.state.state == 'UNINITIALIZED' or from_database_only: + return utils.del_db_object(session, host) + else: + logging.info( + 'send del host %s task to celery', host_id + ) + if not user: + user_id = host.creator_id + user_dict = user_api.get_user(user_id, session=session) + user_email = user_dict['email'] + else: + user_email = user.email + from compass.tasks import client as celery_client + celery_client.celery.send_task( + 'compass.tasks.delete_host', + ( + user.email, host.id, cluster_ids + ), + queue=user_email, + exchange=user_email, + routing_key=user_email + ) + return { + 'status': 'delete action sent', + 'host': host, + } + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_CONFIG +) +@utils.wrap_to_dict(RESP_CONFIG_FIELDS) +def get_host_config(host_id, user=None, session=None, **kwargs): + """Get host config.""" + return _get_host(host_id, session=session) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_CONFIG +) +@utils.wrap_to_dict(RESP_DEPLOYED_CONFIG_FIELDS) +def get_host_deployed_config(host_id, user=None, session=None, **kwargs): + """Get host deployed config.""" + return _get_host(host_id, session=session) + + +# replace os_config to deployed_os_config in kwargs. +@utils.replace_filters( + os_config='deployed_os_config' +) +@utils.supported_filters( + UPDATED_DEPLOYED_CONFIG_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_CONFIG +) +@utils.wrap_to_dict(RESP_CONFIG_FIELDS) +def update_host_deployed_config(host_id, user=None, session=None, **kwargs): + """Update host deployed config.""" + host = _get_host(host_id, session=session) + check_host_editable(host, user=user) + check_host_validated(host) + return utils.update_db_object(session, host, **kwargs) + + +def _host_os_config_validates( + config, host, session=None, user=None, **kwargs +): + """Check host os config's validation.""" + metadata_api.validate_os_config( + config, host.os_id + ) + + +@utils.input_validates_with_args( + put_os_config=_host_os_config_validates +) +@utils.output_validates_with_args( + os_config=_host_os_config_validates +) +@utils.wrap_to_dict(RESP_CONFIG_FIELDS) +def _update_host_config(host, session=None, user=None, **kwargs): + """Update host config.""" + check_host_editable(host, user=user) + return utils.update_db_object(session, host, **kwargs) + + +# replace os_config to put_os_config in kwargs. +# It tells db the os_config will be updated not patched. +@utils.replace_filters( + os_config='put_os_config' +) +@utils.supported_filters( + UPDATED_CONFIG_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_CONFIG +) +def update_host_config(host_id, user=None, session=None, **kwargs): + """Update host config.""" + host = _get_host(host_id, session=session) + return _update_host_config( + host, session=session, user=user, **kwargs + ) + + +# replace os_config to patched_os_config in kwargs. +# It tells db os_config will be patched not be updated. +@utils.replace_filters( + os_config='patched_os_config' +) +@utils.supported_filters( + PATCHED_CONFIG_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_CONFIG +) +def patch_host_config(host_id, user=None, session=None, **kwargs): + """Patch host config.""" + host = _get_host(host_id, session=session) + return _update_host_config( + host, session=session, user=user, **kwargs + ) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEL_HOST_CONFIG +) +@utils.wrap_to_dict(RESP_CONFIG_FIELDS) +def del_host_config(host_id, user=None, session=None): + """delete a host config.""" + host = _get_host(host_id, session=session) + check_host_editable(host, user=user) + return utils.update_db_object( + session, host, os_config={}, config_validated=False + ) + + +@utils.supported_filters( + optional_support_keys=SUPPORTED_NETOWORK_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_NETWORKS +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def list_host_networks(host_id, user=None, session=None, **filters): + """Get host networks for a host.""" + host = _get_host(host_id, session=session) + return utils.list_db_objects( + session, models.HostNetwork, + host_id=host.id, **filters + ) + + +@utils.supported_filters( + optional_support_keys=SUPPORTED_NETOWORK_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_NETWORKS +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def list_hostnetworks(user=None, session=None, **filters): + """Get host networks.""" + return utils.list_db_objects( + session, models.HostNetwork, **filters + ) + + +def _get_hostnetwork(host_network_id, session=None, **kwargs): + """Get hostnetwork by hostnetwork id.""" + if isinstance(host_network_id, (int, long)): + return utils.get_db_object( + session, models.HostNetwork, + id=host_network_id, **kwargs + ) + raise exception.InvalidParameter( + 'host network id %s type is not int compatible' % host_network_id + ) + + +def _get_host_network(host_id, host_network_id, session=None, **kwargs): + """Get hostnetwork by host id and hostnetwork id.""" + host = _get_host(host_id, session=session) + host_network = _get_hostnetwork(host_network_id, session=session, **kwargs) + if host_network.host_id != host.id: + raise exception.RecordNotExists( + 'host %s does not own host network %s' % ( + host.id, host_network.id + ) + ) + return host_network + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_NETWORKS +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def get_host_network( + host_id, host_network_id, + user=None, session=None, **kwargs +): + """Get host network.""" + return _get_host_network( + host_id, host_network_id, session=session + ) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_LIST_HOST_NETWORKS +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def get_hostnetwork(host_network_id, user=None, session=None, **kwargs): + """Get host network.""" + return _get_hostnetwork(host_network_id, session=session) + + +@utils.supported_filters( + ADDED_NETWORK_FIELDS, + optional_support_keys=OPTIONAL_ADDED_NETWORK_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@utils.input_validates( + ip=utils.check_ip +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def _add_host_network( + host_id, exception_when_existing=True, + session=None, user=None, interface=None, ip=None, **kwargs +): + """Add hostnetwork to a host.""" + host = _get_host(host_id, session=session) + check_host_editable(host, user=user) + user_id = user.id + return utils.add_db_object( + session, models.HostNetwork, + exception_when_existing, + host.id, interface, user_id, ip=ip, **kwargs + ) + + +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_NETWORK +) +def add_host_network( + host_id, exception_when_existing=True, + interface=None, user=None, session=None, **kwargs +): + """Create a hostnetwork to a host.""" + return _add_host_network( + host_id, + exception_when_existing, + interface=interface, session=session, user=user, **kwargs + ) + + +def _get_hostnetwork_by_ip( + ip, session=None, **kwargs +): + ip_int = long(netaddr.IPAddress(ip)) + return utils.get_db_object( + session, models.HostNetwork, + ip_int=ip_int, **kwargs + ) + + +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_NETWORK +) +def add_host_networks( + exception_when_existing=False, + data=[], user=None, session=None +): + """Create host networks.""" + hosts = [] + failed_hosts = [] + for host_data in data: + host_id = host_data['host_id'] + host = _get_host(host_id, session=session) + networks = host_data['networks'] + host_networks = [] + failed_host_networks = [] + for network in networks: + host_network = _get_hostnetwork_by_ip( + network['ip'], session=session, + exception_when_missing=False + ) + if ( + host_network and not ( + host_network.host_id == host.id and + host_network.interface == network['interface'] + ) + ): + logging.error('ip %s exists in host network %s' % ( + network['ip'], host_network.id + )) + failed_host_networks.append(network) + else: + host_networks.append(_add_host_network( + host.id, exception_when_existing, + session=session, user=user, **network + )) + if host_networks: + hosts.append({'host_id': host.id, 'networks': host_networks}) + if failed_host_networks: + failed_hosts.append({ + 'host_id': host.id, 'networks': failed_host_networks + }) + return { + 'hosts': hosts, + 'failed_hosts': failed_hosts + } + + +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def _update_host_network( + host_network, session=None, user=None, **kwargs +): + """Update host network.""" + check_host_editable(host_network.host, user=user) + return utils.update_db_object(session, host_network, **kwargs) + + +@utils.supported_filters( + optional_support_keys=UPDATED_NETWORK_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@utils.input_validates( + ip=utils.check_ip +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_NETWORK +) +def update_host_network( + host_id, host_network_id, user=None, session=None, **kwargs +): + """Update a host network by host id and host network id.""" + host = _get_host( + host_id, session=session + ) + if host.state.state == "SUCCESSFUL" and not host.reinstall_os: + logging.info("ignoring updating request for successful hosts") + return {} + + host_network = _get_host_network( + host_id, host_network_id, session=session + ) + return _update_host_network( + host_network, session=session, user=user, **kwargs + ) + + +@utils.supported_filters( + optional_support_keys=UPDATED_NETWORK_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@utils.input_validates( + ip=utils.check_ip +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_ADD_HOST_NETWORK +) +def update_hostnetwork(host_network_id, user=None, session=None, **kwargs): + """Update a host network by host network id.""" + host_network = _get_hostnetwork( + host_network_id, session=session + ) + return _update_host_network( + host_network, session=session, user=user, **kwargs + ) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEL_HOST_NETWORK +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def del_host_network( + host_id, host_network_id, user=None, + session=None, **kwargs +): + """Delete a host network by host id and host network id.""" + host_network = _get_host_network( + host_id, host_network_id, session=session + ) + check_host_editable(host_network.host, user=user) + return utils.del_db_object(session, host_network) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEL_HOST_NETWORK +) +@utils.wrap_to_dict(RESP_NETWORK_FIELDS) +def del_hostnetwork(host_network_id, user=None, session=None, **kwargs): + """Delete a host network by host network id.""" + host_network = _get_hostnetwork( + host_network_id, session=session + ) + check_host_editable(host_network.host, user=user) + return utils.del_db_object(session, host_network) + + +@utils.supported_filters([]) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_GET_HOST_STATE +) +@utils.wrap_to_dict(RESP_STATE_FIELDS) +def get_host_state(host_id, user=None, session=None, **kwargs): + """Get host state info.""" + return _get_host(host_id, session=session).state + + +@utils.supported_filters( + optional_support_keys=UPDATED_STATE_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_UPDATE_HOST_STATE +) +@utils.wrap_to_dict(RESP_STATE_FIELDS) +def update_host_state(host_id, user=None, session=None, **kwargs): + """Update a host state.""" + host = _get_host(host_id, session=session) + utils.update_db_object(session, host.state, **kwargs) + return host.state + + +@util.deprecated +@utils.supported_filters( + optional_support_keys=UPDATED_STATE_INTERNAL_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_UPDATE_HOST_STATE +) +@utils.wrap_to_dict(['status', 'host']) +def update_host_state_internal( + host_id, from_database_only=False, + user=None, session=None, **kwargs +): + """Update a host state. + + This function is called when host os is installed. + If from_database_only, the state is updated in database. + Otherwise a celery task sent to os installer and package installer + to do some future actions. + """ + # TODO(xicheng): should be merged into update_host_state + host = _get_host(host_id, session=session) + logging.info("======host state: %s", host.state) + if 'ready' in kwargs and kwargs['ready'] and not host.state.ready: + ready_triggered = True + else: + ready_triggered = False + clusterhosts_ready = {} + clusters_os_ready = {} + if ready_triggered: + for clusterhost in host.clusterhosts: + cluster = clusterhost.cluster + if cluster.flavor_name: + clusterhosts_ready[cluster.id] = False + else: + clusterhosts_ready[cluster.id] = True + all_os_ready = True + for clusterhost_in_cluster in cluster.clusterhosts: + host_in_cluster = clusterhost_in_cluster.host + if host_in_cluster.id == host.id: + continue + if not host_in_cluster.state.ready: + all_os_ready = False + clusters_os_ready[cluster.id] = all_os_ready + logging.debug('host %s ready: %s', host_id, ready_triggered) + logging.debug("clusterhosts_ready is: %s", clusterhosts_ready) + logging.debug("clusters_os_ready is %s", clusters_os_ready) + + if not ready_triggered or from_database_only: + logging.debug('%s state is set to %s', host.name, kwargs) + utils.update_db_object(session, host.state, **kwargs) + if not host.state.ready: + for clusterhost in host.clusterhosts: + utils.update_db_object( + session, clusterhost.state, ready=False + ) + utils.update_db_object( + session, clusterhost.cluster.state, ready=False + ) + status = '%s state is updated' % host.name + else: + if not user: + user_id = host.creator_id + user_dict = user_api.get_user(user_id, session=session) + user_email = user_dict['email'] + else: + user_email = user.email + from compass.tasks import client as celery_client + celery_client.celery.send_task( + 'compass.tasks.os_installed', + ( + host.id, clusterhosts_ready, + clusters_os_ready + ), + queue=user_email, + exchange=user_email, + routing_key=user_email + ) + status = '%s: clusterhosts ready %s clusters os ready %s' % ( + host.name, clusterhosts_ready, clusters_os_ready + ) + logging.info('action status: %s', status) + return { + 'status': status, + 'host': host.state + } + + +@utils.supported_filters([]) +@database.run_in_session() +@utils.wrap_to_dict(RESP_LOG_FIELDS) +def get_host_log_histories(host_id, user=None, session=None, **kwargs): + """Get host log history.""" + host = _get_host(host_id, session=session) + return utils.list_db_objects( + session, models.HostLogHistory, id=host.id, **kwargs + ) + + +def _get_host_log_history(host_id, filename, session=None, **kwargs): + host = _get_host(host_id, session=session) + return utils.get_db_object( + session, models.HostLogHistory, id=host.id, + filename=filename, **kwargs + ) + + +@utils.supported_filters([]) +@database.run_in_session() +@utils.wrap_to_dict(RESP_LOG_FIELDS) +def get_host_log_history(host_id, filename, user=None, session=None, **kwargs): + """Get host log history.""" + return _get_host_log_history( + host_id, filename, session=session + ) + + +@utils.supported_filters( + optional_support_keys=UPDATED_LOG_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@utils.wrap_to_dict(RESP_LOG_FIELDS) +def update_host_log_history( + host_id, filename, user=None, + session=None, **kwargs +): + """Update a host log history.""" + host_log_history = _get_host_log_history( + host_id, filename, session=session + ) + return utils.update_db_object(session, host_log_history, **kwargs) + + +@utils.supported_filters( + ADDED_LOG_FIELDS, + optional_support_keys=UPDATED_LOG_FIELDS, + ignore_support_keys=IGNORE_FIELDS +) +@database.run_in_session() +@utils.wrap_to_dict(RESP_LOG_FIELDS) +def add_host_log_history( + host_id, exception_when_existing=False, + filename=None, user=None, session=None, **kwargs +): + """add a host log history.""" + host = _get_host(host_id, session=session) + 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( + permission.PERMISSION_DEPLOY_HOST +) +@utils.wrap_to_dict( + RESP_DEPLOY_FIELDS, + host=RESP_CONFIG_FIELDS +) +def poweron_host( + host_id, poweron={}, user=None, session=None, **kwargs +): + """power on host.""" + from compass.tasks import client as celery_client + host = _get_host(host_id, session=session) + check_host_validated(host) + if not user: + user_id = host.creator_id + user_dict = user_api.get_user(user_id, session=session) + user_email = user_dict['email'] + else: + user_email = user.email + celery_client.celery.send_task( + 'compass.tasks.poweron_host', + (host.id,), + queue=user_email, + exchange=user_email, + routing_key=user_email + ) + return { + 'status': 'poweron %s action sent' % host.name, + 'host': host + } + + +@utils.supported_filters(optional_support_keys=['poweroff']) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEPLOY_HOST +) +@utils.wrap_to_dict( + RESP_DEPLOY_FIELDS, + host=RESP_CONFIG_FIELDS +) +def poweroff_host( + host_id, poweroff={}, user=None, session=None, **kwargs +): + """power off host.""" + from compass.tasks import client as celery_client + host = _get_host(host_id, session=session) + check_host_validated(host) + if not user: + user_id = host.creator_id + user_dict = user_api.get_user(user_id, session=session) + user_email = user_dict['email'] + else: + user_email = user.email + celery_client.celery.send_task( + 'compass.tasks.poweroff_host', + (host.id,), + queue=user_email, + exchange=user_email, + routing_key=user_email + ) + return { + 'status': 'poweroff %s action sent' % host.name, + 'host': host + } + + +@utils.supported_filters(optional_support_keys=['reset']) +@database.run_in_session() +@user_api.check_user_permission( + permission.PERMISSION_DEPLOY_HOST +) +@utils.wrap_to_dict( + RESP_DEPLOY_FIELDS, + host=RESP_CONFIG_FIELDS +) +def reset_host( + host_id, reset={}, user=None, session=None, **kwargs +): + """reset host.""" + from compass.tasks import client as celery_client + host = _get_host(host_id, session=session) + check_host_validated(host) + if not user: + user_id = host.creator_id + user_dict = user_api.get_user(user_id, session=session) + user_email = user_dict['email'] + else: + user_email = user.email + celery_client.celery.send_task( + 'compass.tasks.reset_host', + (host.id,), + queue=user_email, + exchange=user_email, + routing_key=user_email + ) + return { + 'status': 'reset %s action sent' % host.name, + 'host': host + } |