tacker/tacker/sol_refactored/mgmt_drivers/server_notification.py

257 lines
10 KiB
Python

# Copyright (C) 2022 Fujitsu
# All Rights Reserved.
#
# 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.
import os
import pickle
import sys
from oslo_log import log as logging
from tacker.common import exceptions as common_ex
from tacker.common import rpc
from tacker import context
from tacker.sol_refactored.common import config as cfg
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import http_client
from tacker.sol_refactored.conductor import conductor_rpc_v2
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
class ServerNotificationMgmtDriver(object):
def __init__(self, req, inst, grant_req, grant, csar_dir):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
auth_handle = http_client.NoAuthHandle()
self.client = http_client.HttpClient(auth_handle)
CONF(project='tacker')
rpc.init(CONF)
self.rpc = conductor_rpc_v2.VnfLcmRpcApiV2()
def make_output_dict(self):
return {'vnf_instance': self.inst}
def request_remove_timer(self, vnf_instance_id):
self.rpc.server_notification_remove_timer(
context.get_admin_context(), vnf_instance_id)
def _request_unregister(
self, server_notifier_uri, tenant, server_id, alarm_id):
try:
url = (f'{server_notifier_uri}/v2/{tenant}/servers/{server_id}/'
f'alarms/{alarm_id}')
resp, _ = self.client.do_request(
url, "DELETE")
if resp.status_code >= 400:
LOG.error(
"server_notification unregistration is failed: %d.",
resp.status_code)
else:
LOG.debug(
"server_notification unregistration is processed: %d.",
resp.status_code)
except sol_ex.SolException as e:
# Even if unregistration is failed for a single alarm_id,
# Unregistration should be done for remaining alarm_ids.
LOG.error(str(e))
def request_unregister(
self, isall=True, vnfc_res_ids=None):
server_notifier_uri, _, tenant = self.get_params()
found = False
res_ids = vnfc_res_ids if vnfc_res_ids else []
for rsc in self.inst['instantiatedVnfInfo']['vnfcResourceInfo']:
if ('metadata' in rsc and
'server_notification' in rsc['metadata'] and (isall or
rsc['computeResource']['resourceId'] in res_ids)):
found = True
alarm_id = rsc['metadata']['server_notification']['alarmId']
del rsc['metadata']['server_notification']
server_id = rsc['computeResource']['resourceId']
self._request_unregister(
server_notifier_uri, tenant, server_id, alarm_id)
return found
def request_register_cancel(self, rsc_list):
server_notifier_uri, _, tenant = self.get_params()
for rsc in rsc_list:
if ('metadata' in rsc and
'server_notification' in rsc['metadata']):
alarm_id = rsc['metadata']['server_notification']['alarmId']
del rsc['metadata']['server_notification']
server_id = rsc['computeResource']['resourceId']
self._request_unregister(
server_notifier_uri, tenant, server_id, alarm_id)
def _request_register(self, vnfc_resource):
server_id = vnfc_resource['computeResource']['resourceId']
server_notifier_uri, fault_id, tenant = self.get_params()
url = f'{server_notifier_uri}/v2/{tenant}/servers/{server_id}/alarms'
endpoint = CONF.v2_vnfm.endpoint
prefix = CONF.server_notification.uri_path_prefix
_id = self.inst['id']
fault_action = (f'{endpoint}/{prefix}/vnf_instances/{_id}/'
f'servers/{server_id}/notify')
req_body = {
'fault_action': fault_action,
'fault_id': fault_id
}
resp, res_body = self.client.do_request(
url, "POST", body=req_body)
if resp.status_code >= 400 or 'alarm_id' not in res_body:
msg = ("server_notification registration is "
f"failed: {resp.status_code}.")
raise common_ex.MgmtDriverOtherError(error_message=msg)
if 'metadata' not in vnfc_resource:
vnfc_resource['metadata'] = {}
vnfc_resource['metadata']['server_notification'] = {
'alarmId': res_body['alarm_id']}
LOG.debug(
"server_notification registration is processed: %d. "
"alarm_id: %s", resp.status_code, res_body['alarm_id'])
return {'alarmId': res_body['alarm_id'], 'serverId': server_id}
def request_register(self):
rsc_list = []
for rsc in self.inst['instantiatedVnfInfo']['vnfcResourceInfo']:
if ('metadata' not in rsc or
'server_notification' not in rsc['metadata']):
try:
self._request_register(rsc)
rsc_list.append(rsc)
except sol_ex.SolException as e:
LOG.error(str(e))
self.request_register_cancel(rsc_list)
msg = "ServerNotification registration is failed."
raise common_ex.MgmtDriverOtherError(
error_message=msg) from e
def get_params(self):
server_notifier_uri = None
fault_id = None
tenant = None
additional_params = self.req.get('additionalParams', None)
if 'instantiatedVnfInfo' not in self.inst:
return (None, None, None)
vnf_info = self.inst['instantiatedVnfInfo']
if (additional_params and
'ServerNotifierUri' in additional_params and
'ServerNotifierFaultID' in additional_params):
server_notifier_uri = additional_params['ServerNotifierUri']
fault_id = additional_params['ServerNotifierFaultID']
elif (vnf_info and 'metadata' in vnf_info and
'ServerNotifierUri' in vnf_info['metadata'] and
'ServerNotifierFaultID' in vnf_info['metadata']):
server_notifier_uri = vnf_info['metadata']['ServerNotifierUri']
fault_id = vnf_info['metadata']['ServerNotifierFaultID']
if 'vimConnectionInfo' in self.inst:
for vim_info in self.inst['vimConnectionInfo'].values():
if ('accessInfo' in vim_info and
'project' in vim_info['accessInfo']):
tenant = vim_info['accessInfo']['project']
if server_notifier_uri and fault_id and tenant:
return (server_notifier_uri, fault_id, tenant)
return (None, None, None)
def terminate_start(self):
at_least_one_id_unregistered = self.request_unregister()
if at_least_one_id_unregistered:
self.request_remove_timer(self.inst['id'])
for key in ['ServerNotifierUri', 'ServerNotifierFaultID']:
if ('metadata' in self.inst['instantiatedVnfInfo'] and
key in self.inst['instantiatedVnfInfo']['metadata']):
del self.inst['instantiatedVnfInfo']['metadata'][key]
return self.make_output_dict()
def scale_start(self):
if self.req['type'] != 'SCALE_IN':
return
vnfc_res_ids = [res_def['resource']['resourceId']
for res_def in self.grant_req['removeResources']
if res_def.get('type', None) == 'COMPUTE']
self.request_unregister(
isall=False, vnfc_res_ids=vnfc_res_ids)
return self.make_output_dict()
def heal_start(self):
isall = ('additionalParams' in self.req and
self.req['additionalParams'].get('all', False) and
'vnfcInstanceId' not in self.req)
vnfc_res_ids = [res_def['resource']['resourceId']
for res_def in self.grant_req['removeResources']
if res_def.get('type', None) == 'COMPUTE']
self.request_unregister(
isall=isall, vnfc_res_ids=vnfc_res_ids)
return self.make_output_dict()
def instantiate_end(self):
self.request_register()
server_notifier_uri, fault_id, _ = self.get_params()
vnf_info = self.inst['instantiatedVnfInfo']
if 'metadata' not in vnf_info:
vnf_info['metadata'] = {}
vnf_info['metadata']['ServerNotifierUri'] = server_notifier_uri
vnf_info['metadata']['ServerNotifierFaultID'] = fault_id
return self.make_output_dict()
def scale_end(self):
if self.req['type'] != 'SCALE_OUT':
return
self.request_register()
return self.make_output_dict()
def heal_end(self):
self.request_register()
return self.make_output_dict()
def instantiate_start(self):
pass
def terminate_end(self):
pass
def main():
script_dict = pickle.load(sys.stdin.buffer)
operation = script_dict['operation']
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
script = ServerNotificationMgmtDriver(
req, inst, grant_req, grant, csar_dir)
output_dict = getattr(script, operation)()
sys.stdout.buffer.write(pickle.dumps(output_dict))
sys.stdout.flush()
if __name__ == "__main__":
try:
main()
os._exit(0)
except Exception as ex:
sys.stderr.write(str(ex))
sys.stderr.flush()
os._exit(1)