Controller Services swact/failover time reduction

Add full support for Active/Active redudancy model.
1. services could have enable dependency to services in other service
groups (standby group)
2. An active/active service failure will degraded the service group it
is in
3. A failure of active/active service would not prevent a swact
4. Locking a controller that is sole active/active service provider will
be rejected. But lock with force option will still proceed to lock the
node.
5. sm-api bind to port 7777 on mgmt interface. (was localhost:7777)

Change-Id: I62fbfa8ba66a055ee7cda4f995b3a4a4e5b3fdde
This commit is contained in:
Bin Qian 2018-06-01 13:45:08 -04:00 committed by Jack Ding
parent a691d3f9bb
commit 80c8a52d58
2 changed files with 80 additions and 11 deletions

View File

@ -86,10 +86,12 @@ from sysinv.openstack.common import log
from sysinv.openstack.common import uuidutils
from sysinv.openstack.common.gettextutils import _
from sysinv.common.storage_backend_conf import StorageBackendConfig
from sysinv.common import health
LOG = log.getLogger(__name__)
KEYRING_BM_SERVICE = "BM"
ERR_CODE_LOCK_SOLE_SERVICE_PROVIDER = "-1003"
def _get_controller_address(hostname):
@ -4621,6 +4623,33 @@ class HostController(rest.RestController):
constants.CONTROLLER_1_HOSTNAME,
constants.STORAGE_0_HOSTNAME))
if not force:
# sm-lock-pre-check
node_name = hostupdate.displayid
response = sm_api.lock_pre_check(node_name, timeout=30)
if response:
error_code = response.get('error_code')
if ERR_CODE_LOCK_SOLE_SERVICE_PROVIDER == error_code:
impact_svc_list = response.get('impact_service_list')
svc_list = ','.join(impact_svc_list)
if len(impact_svc_list) > 1:
msg = _("Services {svc_list} are only running on "
"{host}, locking {host} will result "
"service outage. If lock {host} is required, "
"please use \"force lock\" command.").format(
svc_list=svc_list, host=node_name)
else:
msg = _("Service {svc_list} is only running on "
"{host}, locking {host} will result "
"service outage. If lock {host} is required, "
"please use \"force lock\" command.").format(
svc_list=svc_list, host=node_name)
raise wsme.exc.ClientSideError(msg)
elif "0" != error_code:
raise wsme.exc.ClientSideError(
_("%s" % response['error_details']))
def check_unlock_controller(self, hostupdate):
"""Pre unlock semantic checks for controller"""
LOG.info("%s ihost check_unlock_controller" % hostupdate.displayid)
@ -4988,10 +5017,20 @@ class HostController(rest.RestController):
if (ihost_ctr.availability ==
constants.AVAILABILITY_DEGRADED):
raise wsme.exc.ClientSideError(
_("%s has degraded availability status. "
"Standby controller must be in available status.") %
(ihost_ctr.hostname))
health_helper = health.Health(pecan.request.dbapi)
degrade_alarms = health_helper.get_alarms_degrade(
alarm_ignore_list=[
fm_constants.FM_ALARM_ID_HA_SERVICE_GROUP_STATE,
fm_constants.FM_ALARM_ID_HA_SERVICE_GROUP_REDUNDANCY,
fm_constants.FM_ALARM_ID_HA_NODE_LICENSE,
fm_constants.FM_ALARM_ID_HA_COMMUNICATION_FAILURE
],
entity_instance_id_filter=ihost_ctr.hostname)
if degrade_alarms:
raise wsme.exc.ClientSideError(
_("%s has degraded availability status. "
"Standby controller must be in available status.") %
(ihost_ctr.hostname))
if constants.COMPUTE in ihost_ctr.subfunctions:
if (ihost_ctr.subfunction_oper !=

View File

@ -4,18 +4,24 @@
# SPDX-License-Identifier: Apache-2.0
#
import json
import socket
from rest_api import rest_api_request
from sysinv.openstack.common import log
LOG = log.getLogger(__name__)
SM_API_HOST = socket.gethostname()
SM_API_PORT = 7777
SM_API_PATH = "http://{host}:{port}".\
format(host=SM_API_HOST, port=SM_API_PORT)
def swact_pre_check(hostname, timeout):
"""
Sends a Swact Pre-Check command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/servicenode/%s" % hostname
api_cmd_headers = dict()
@ -35,11 +41,35 @@ def swact_pre_check(hostname, timeout):
return response
def lock_pre_check(hostname, timeout):
"""
Sends a Lock Pre-Check command to SM.
"""
api_cmd = SM_API_PATH
api_cmd += "/v1/servicenode/%s" % hostname
api_cmd_headers = dict()
api_cmd_headers['Content-type'] = "application/json"
api_cmd_headers['User-Agent'] = "sysinv/1.0"
api_cmd_payload = dict()
api_cmd_payload['origin'] = "sysinv"
api_cmd_payload['action'] = "lock-pre-check"
api_cmd_payload['admin'] = "unknown"
api_cmd_payload['oper'] = "unknown"
api_cmd_payload['avail'] = ""
response = rest_api_request(None, "PATCH", api_cmd, api_cmd_headers,
json.dumps(api_cmd_payload), timeout)
return response
def service_list():
"""
Sends a service list command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/services"
api_cmd_headers = dict()
@ -56,7 +86,7 @@ def service_show(hostname):
"""
Sends a service show command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/services/%s" % hostname
api_cmd_headers = dict()
@ -72,7 +102,7 @@ def servicenode_list():
"""
Sends a service list command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/nodes"
api_cmd_headers = dict()
@ -89,7 +119,7 @@ def servicenode_show(hostname):
"""
Sends a service show command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/nodes/%s" % hostname
api_cmd_headers = dict()
@ -106,7 +136,7 @@ def sm_servicegroup_list():
"""
Sends a service list command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/sm_sda"
api_cmd_headers = dict()
@ -128,7 +158,7 @@ def sm_servicegroup_show(hostname):
"""
Sends a service show command to SM.
"""
api_cmd = "http://localhost:7777"
api_cmd = SM_API_PATH
api_cmd += "/v1/sm_sda/%s" % hostname
api_cmd_headers = dict()