420 lines
15 KiB
Python
Executable File
420 lines
15 KiB
Python
Executable File
#
|
|
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import six
|
|
|
|
from nfv_common import debug
|
|
from nfv_common.helpers import Constant
|
|
from nfv_common.helpers import Singleton
|
|
|
|
from nfv_vim.objects._object import ObjectData
|
|
|
|
from nfv_vim import nfvi
|
|
|
|
DLOG = debug.debug_get_logger('nfv_vim.objects.guest_services')
|
|
|
|
|
|
@six.add_metaclass(Singleton)
|
|
class GuestServiceNames(object):
|
|
"""
|
|
Guest Services Name Constants
|
|
"""
|
|
HEARTBEAT = Constant('heartbeat')
|
|
|
|
|
|
# Guest Services Constant Instantiation
|
|
GUEST_SERVICE_NAME = GuestServiceNames()
|
|
|
|
|
|
class GuestServices(ObjectData):
|
|
"""
|
|
Guest Services Object
|
|
"""
|
|
SERVICE_NOT_CONFIGURED = "not-configured"
|
|
SERVICE_CONFIGURED = "configured"
|
|
SERVICE_ENABLING = "enabling"
|
|
SERVICE_DISABLING = "disabling"
|
|
SERVICE_ENABLED = "enabled"
|
|
SERVICE_DISABLED = "disabled"
|
|
SERVICE_DELETING = "deleting"
|
|
|
|
def __init__(self, services=None, nfvi_guest_services=None):
|
|
super(GuestServices, self).__init__('1.0.0')
|
|
|
|
if services is None:
|
|
self._services = dict()
|
|
else:
|
|
self._services = services
|
|
|
|
if nfvi_guest_services is not None:
|
|
if 0 == len(nfvi_guest_services):
|
|
self._nfvi_guest_services = None
|
|
else:
|
|
self._nfvi_guest_services = nfvi_guest_services
|
|
else:
|
|
self._nfvi_guest_services = None
|
|
|
|
@staticmethod
|
|
def _convert_nfvi_service_name(nfvi_service_name):
|
|
"""
|
|
Returns the service name given the nfvi service name
|
|
"""
|
|
if nfvi.objects.v1.GUEST_SERVICE_NAME.HEARTBEAT == nfvi_service_name:
|
|
return GUEST_SERVICE_NAME.HEARTBEAT
|
|
return None
|
|
|
|
@staticmethod
|
|
def _convert_nfvi_service_state(nfvi_service_admin_state,
|
|
nfvi_service_oper_state):
|
|
"""
|
|
Returns the service state given the nfvi service state
|
|
"""
|
|
if nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED \
|
|
== nfvi_service_admin_state:
|
|
return GuestServices.SERVICE_DISABLED
|
|
else:
|
|
if nfvi.objects.v1.GUEST_SERVICE_OPER_STATE.ENABLED \
|
|
== nfvi_service_oper_state:
|
|
return GuestServices.SERVICE_ENABLED
|
|
else:
|
|
return GuestServices.SERVICE_ENABLING
|
|
|
|
@staticmethod
|
|
def _get_nfvi_service_name(service_name):
|
|
"""
|
|
Returns the nfvi service name
|
|
"""
|
|
if GUEST_SERVICE_NAME.HEARTBEAT == service_name:
|
|
return nfvi.objects.v1.GUEST_SERVICE_NAME.HEARTBEAT
|
|
return None
|
|
|
|
@staticmethod
|
|
def _get_nfvi_service_admin_state(service_state):
|
|
"""
|
|
Returns the nfvi service state
|
|
"""
|
|
if GuestServices.SERVICE_NOT_CONFIGURED == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED
|
|
|
|
elif GuestServices.SERVICE_CONFIGURED == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED
|
|
|
|
elif GuestServices.SERVICE_ENABLING == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.UNLOCKED
|
|
|
|
elif GuestServices.SERVICE_DISABLING == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED
|
|
|
|
elif GuestServices.SERVICE_ENABLED == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.UNLOCKED
|
|
|
|
elif GuestServices.SERVICE_DISABLED == service_state:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED
|
|
|
|
else:
|
|
return nfvi.objects.v1.GUEST_SERVICE_ADMIN_STATE.LOCKED
|
|
|
|
@property
|
|
def services(self):
|
|
"""
|
|
Returns a list of services
|
|
"""
|
|
return self._services.keys()
|
|
|
|
@property
|
|
def state(self):
|
|
"""
|
|
Returns the overall state of the guest services
|
|
"""
|
|
def update_overall_state(current_state, state):
|
|
"""
|
|
Returns the overall_state updated if needed
|
|
"""
|
|
if current_state is None:
|
|
return state
|
|
|
|
if GuestServices.SERVICE_DELETING == current_state:
|
|
return GuestServices.SERVICE_DELETING
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state:
|
|
if GuestServices.SERVICE_NOT_CONFIGURED == state:
|
|
return GuestServices.SERVICE_NOT_CONFIGURED
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state \
|
|
and GuestServices.SERVICE_NOT_CONFIGURED != current_state:
|
|
if GuestServices.SERVICE_CONFIGURED == state:
|
|
return GuestServices.SERVICE_CONFIGURED
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state \
|
|
and GuestServices.SERVICE_NOT_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_CONFIGURED != current_state:
|
|
if GuestServices.SERVICE_DISABLING == state:
|
|
return GuestServices.SERVICE_DISABLING
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state \
|
|
and GuestServices.SERVICE_NOT_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_DISABLING != current_state:
|
|
if GuestServices.SERVICE_DISABLED == state:
|
|
return GuestServices.SERVICE_DISABLED
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state \
|
|
and GuestServices.SERVICE_NOT_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_DISABLING != current_state \
|
|
and GuestServices.SERVICE_DISABLED != current_state:
|
|
if GuestServices.SERVICE_ENABLING == state:
|
|
return GuestServices.SERVICE_ENABLING
|
|
|
|
if GuestServices.SERVICE_DELETING != current_state \
|
|
and GuestServices.SERVICE_NOT_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_CONFIGURED != current_state \
|
|
and GuestServices.SERVICE_DISABLING != current_state \
|
|
and GuestServices.SERVICE_DISABLED != current_state \
|
|
and GuestServices.SERVICE_ENABLING != current_state:
|
|
if GuestServices.SERVICE_ENABLED == state:
|
|
return GuestServices.SERVICE_ENABLED
|
|
|
|
return current_state
|
|
|
|
overall_state = None
|
|
for _, service_state in self._services.items():
|
|
overall_state = update_overall_state(overall_state, service_state)
|
|
|
|
return overall_state
|
|
|
|
@property
|
|
def communication_establish_timeout(self):
|
|
"""
|
|
Returns the maximum amount of time in seconds to wait for the guest
|
|
to establish communication, includes reboot time plus heartbeat
|
|
initialization time required
|
|
"""
|
|
restart_timeout = 300
|
|
|
|
if self._nfvi_guest_services is not None:
|
|
nfvi_service_name \
|
|
= self._get_nfvi_service_name(GUEST_SERVICE_NAME.HEARTBEAT)
|
|
|
|
for nfvi_service in self._nfvi_guest_services:
|
|
if nfvi_service_name == nfvi_service.name:
|
|
if 0 != nfvi_service.restart_timeout:
|
|
restart_timeout = nfvi_service.restart_timeout
|
|
break
|
|
|
|
return restart_timeout
|
|
|
|
def provision(self, service):
|
|
"""
|
|
Add a service to the list of known services
|
|
"""
|
|
if service not in self._services:
|
|
self._services[service] = GuestServices.SERVICE_NOT_CONFIGURED
|
|
|
|
def are_provisioned(self):
|
|
"""
|
|
Returns true if services have been provisioned
|
|
"""
|
|
return 0 < len(self._services)
|
|
|
|
def are_configured(self):
|
|
"""
|
|
Return true if all guest services are configured
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_NOT_CONFIGURED == self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def are_enabling(self):
|
|
"""
|
|
Return true if all guest services are enabling or are enabled
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_ENABLING != self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def are_enabled(self):
|
|
"""
|
|
Return true if all guest services are enabled
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_ENABLED != self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def are_disabling(self):
|
|
"""
|
|
Return true if all guest services are disabling or are disabled
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_DISABLING != self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def are_disabled(self):
|
|
"""
|
|
Return true if all guest services are disabled
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_DISABLED != self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def are_deleting(self):
|
|
"""
|
|
Return true if all guest services are deleting
|
|
"""
|
|
for service in self._services:
|
|
if GuestServices.SERVICE_DELETING != self._services[service]:
|
|
return False
|
|
return True
|
|
|
|
def configured(self):
|
|
"""
|
|
Set guest services to the configured state
|
|
"""
|
|
for service in self._services:
|
|
self._services[service] = GuestServices.SERVICE_CONFIGURED
|
|
|
|
def enable(self):
|
|
"""
|
|
Set guest services to the enabling state
|
|
"""
|
|
for service in self._services:
|
|
self._services[service] = GuestServices.SERVICE_ENABLING
|
|
|
|
def disable(self):
|
|
"""
|
|
Set guest services to the disabling state
|
|
"""
|
|
for service in self._services:
|
|
self._services[service] = GuestServices.SERVICE_DISABLING
|
|
|
|
def delete(self):
|
|
"""
|
|
Set guest services to the deleting state
|
|
"""
|
|
for service in self._services:
|
|
self._services[service] = GuestServices.SERVICE_DELETING
|
|
|
|
def deleted(self):
|
|
"""
|
|
Delete guest services
|
|
"""
|
|
if self._services is not None:
|
|
del self._services
|
|
self._services = dict()
|
|
|
|
def guest_communication_established(self):
|
|
"""
|
|
Returns true if guest communication has been established
|
|
"""
|
|
state = self._services.get(GUEST_SERVICE_NAME.HEARTBEAT, None)
|
|
return GuestServices.SERVICE_ENABLED == state
|
|
|
|
def get_nfvi_guest_service_names(self):
|
|
"""
|
|
Returns a listing of nfvi guest services and their state
|
|
"""
|
|
nfvi_service_names = list()
|
|
for service_name, service_state in self._services.items():
|
|
nfvi_name = self._get_nfvi_service_name(service_name)
|
|
if nfvi_name is not None:
|
|
nfvi_service_names.append(nfvi_name)
|
|
|
|
return nfvi_service_names
|
|
|
|
def get_nfvi_guest_services(self):
|
|
"""
|
|
Returns a listing of nfvi guest services and their state
|
|
"""
|
|
nfvi_services = list()
|
|
for service_name, service_state in self._services.items():
|
|
nfvi_name = self._get_nfvi_service_name(service_name)
|
|
nfvi_admin_state = self._get_nfvi_service_admin_state(service_state)
|
|
|
|
if nfvi_name is not None:
|
|
nfvi_service = dict()
|
|
nfvi_service['service'] = nfvi_name
|
|
nfvi_service['admin_state'] = nfvi_admin_state
|
|
nfvi_services.append(nfvi_service)
|
|
|
|
return nfvi_services
|
|
|
|
def nfvi_guest_services_update(self, nfvi_guest_services):
|
|
"""
|
|
NFVI Guest Services Update
|
|
"""
|
|
for nfvi_service in nfvi_guest_services:
|
|
# Preserve the restart-timeout, on disables it can be set to zero
|
|
if 0 == nfvi_service.restart_timeout \
|
|
and self._nfvi_guest_services is not None:
|
|
prev_nfvi_service \
|
|
= next((x for x in self._nfvi_guest_services
|
|
if x.name == nfvi_service.name), None)
|
|
if prev_nfvi_service is not None:
|
|
nfvi_service.restart_timeout \
|
|
= prev_nfvi_service.restart_timeout
|
|
|
|
service_name = self._convert_nfvi_service_name(nfvi_service.name)
|
|
service_state = self._convert_nfvi_service_state(
|
|
nfvi_service.admin_state, nfvi_service.oper_state)
|
|
|
|
if service_name is not None:
|
|
current_state = self._services.get(service_name, None)
|
|
if GuestServices.SERVICE_ENABLED == current_state:
|
|
if GuestServices.SERVICE_ENABLING == service_state:
|
|
self._services[service_name] = service_state
|
|
|
|
elif GuestServices.SERVICE_ENABLING == current_state:
|
|
if GuestServices.SERVICE_ENABLED == service_state:
|
|
self._services[service_name] = service_state
|
|
|
|
elif GuestServices.SERVICE_DISABLING == current_state:
|
|
if GuestServices.SERVICE_DISABLED == service_state:
|
|
self._services[service_name] = service_state
|
|
|
|
if self._nfvi_guest_services is not None:
|
|
del self._nfvi_guest_services
|
|
|
|
self._nfvi_guest_services = nfvi_guest_services
|
|
|
|
def nfvi_guest_services_state_update_needed(self):
|
|
"""
|
|
Returns true if the nfvi guest services needs to be updated
|
|
"""
|
|
if not self.are_configured():
|
|
return False
|
|
|
|
for nfvi_service in self._nfvi_guest_services:
|
|
service_name = self._convert_nfvi_service_name(nfvi_service.name)
|
|
service_state = self._services.get(service_name, None)
|
|
if service_state is not None:
|
|
expected_state \
|
|
= self._get_nfvi_service_admin_state(service_state)
|
|
|
|
if nfvi_service.admin_state != expected_state:
|
|
DLOG.verbose("Guest-Services update needed, "
|
|
"admin_state=%s, expected_admin_state=%s"
|
|
% (nfvi_service.admin_state, expected_state))
|
|
return True
|
|
|
|
return False
|
|
|
|
def as_dict(self):
|
|
"""
|
|
Represent Guest Services as dictionary
|
|
"""
|
|
data = dict()
|
|
data['state'] = self.state
|
|
data['services'] = self._services
|
|
data['nfvi_guest_services'] = list()
|
|
if self._nfvi_guest_services is not None:
|
|
for nfvi_service in self._nfvi_guest_services:
|
|
data['nfvi_guest_services'].append(nfvi_service.as_dict())
|
|
return data
|