257 lines
10 KiB
Python
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)
|