# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2012 VMware, Inc.
#
#    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.

"""
Management class for host-related functions (start, reboot, etc).
"""

from oslo_log import log as logging
from oslo_utils import units
from oslo_utils import versionutils
from oslo_vmware import exceptions as vexc

import nova.conf
from nova import context
from nova import exception
from nova import objects
from nova.objects import fields as obj_fields
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util

CONF = nova.conf.CONF
LOG = logging.getLogger(__name__)


def _get_ds_capacity_and_freespace(session, cluster=None,
                                   datastore_regex=None):
    try:
        ds = ds_util.get_datastore(session, cluster,
                                   datastore_regex)
        return ds.capacity, ds.freespace
    except exception.DatastoreNotFound:
        return 0, 0


class VCState(object):
    """Manages information about the vCenter cluster"""

    def __init__(self, session, host_name, cluster, datastore_regex):
        super(VCState, self).__init__()
        self._session = session
        self._host_name = host_name
        self._cluster = cluster
        self._datastore_regex = datastore_regex
        self._stats = {}
        self._auto_service_disabled = False
        about_info = self._session._call_method(vim_util, "get_about_info")
        self._hypervisor_type = about_info.name
        self._hypervisor_version = versionutils.convert_version_to_int(
                str(about_info.version))
        self.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the cluster. If 'refresh' is
        True, run the update first.
        """
        if refresh or not self._stats:
            self.update_status()
        return self._stats

    def update_status(self):
        """Update the current state of the cluster."""
        data = {}
        try:
            capacity, freespace = _get_ds_capacity_and_freespace(self._session,
                self._cluster, self._datastore_regex)

            # Get cpu, memory stats from the cluster
            stats = vm_util.get_stats_from_cluster(self._session,
                                                   self._cluster)
        except (vexc.VimConnectionException, vexc.VimAttributeException) as ex:
            # VimAttributeException is thrown when vpxd service is down
            LOG.warning("Failed to connect with %(node)s. "
                        "Error: %(error)s",
                        {'node': self._host_name, 'error': ex})
            self._set_host_enabled(False)
            return data

        data["vcpus"] = stats['cpu']['vcpus']
        data["disk_total"] = capacity // units.Gi
        data["disk_available"] = freespace // units.Gi
        data["disk_used"] = data["disk_total"] - data["disk_available"]
        data["host_memory_total"] = stats['mem']['total']
        data["host_memory_free"] = stats['mem']['free']
        data["hypervisor_type"] = self._hypervisor_type
        data["hypervisor_version"] = self._hypervisor_version
        data["hypervisor_hostname"] = self._host_name
        data["supported_instances"] = [
            (obj_fields.Architecture.I686,
             obj_fields.HVType.VMWARE,
             obj_fields.VMMode.HVM),
            (obj_fields.Architecture.X86_64,
             obj_fields.HVType.VMWARE,
             obj_fields.VMMode.HVM)]

        self._stats = data
        if self._auto_service_disabled:
            self._set_host_enabled(True)
        return data

    def _set_host_enabled(self, enabled):
        """Sets the compute host's ability to accept new instances."""
        ctx = context.get_admin_context()
        service = objects.Service.get_by_compute_host(ctx, CONF.host)
        service.disabled = not enabled
        service.disabled_reason = 'set by vmwareapi host_state'
        service.save()
        self._auto_service_disabled = service.disabled
