def __init__(self, *args, **kwargs):
     if 'virtual_mem_size' in kwargs and 'num_virtual_cpu' in kwargs and 'image' in kwargs:
         self.memory = kwargs['virtual_mem_size']
         self.cpu = kwargs['num_virtual_cpu']
         self.image = kwargs['image']
     self.network_name = kwargs['network_name'] if 'network_name' in kwargs else None
     self.user_name = kwargs['user_name'] if 'user_name' in kwargs else None
     self.user_public_key = kwargs['user_public_key'] if 'user_public_key' in kwargs else None
     self.config_map_mount_path = kwargs['config_map_mount_path'] if 'config_map_mount_path' in kwargs else None
     self.command = kwargs['command'] if 'command' in kwargs else None
     self.replicas = kwargs['replicas'] if 'replicas' in kwargs else None
     self.labels = kwargs['labels'] if 'labels' in kwargs and isinstance(kwargs['labels'], dict) else None
     if 'ports' in kwargs and 'name_of_service' in kwargs:
         self.name_of_service = kwargs['name_of_service']
     super().__init__(*args, **kwargs)
     self.etcd_client = EtcdClient()
     self.etcd_client.set_deploy_name(instance_name=self.instance_name, pod_name=None)
Exemple #2
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.etcd_client = EtcdClient()
     self.alarm = AlarmEvent()
     global is_running
     if not is_running:
         threading.Thread(
             target=self._get_replica_event,
             args=(self.app_v1.list_deployment_for_all_namespaces,
                   self.deployment_status),
             daemon=True).start()
         threading.Thread(target=partial(self._get_pod_event),
                          daemon=True).start()
         threading.Thread(
             target=self._get_replica_event,
             args=
             (self.kubevirt_api.
              list_virtual_machine_instance_replica_set_for_all_namespaces,
              self.virtual_machine_replica_set),
             daemon=True).start()
         threading.Thread(target=partial(self._get_virtual_machine_event),
                          daemon=True).start()
     is_running = True
Exemple #3
0
 def __init__(self, package_id):
     self.package_id = package_id
     super().__init__(self.get_root_path())
     self.etcd_client = EtcdClient()
Exemple #4
0
class NSLifecycleManagementViewSet(viewsets.ModelViewSet):
    queryset = NsInstance.objects.all()
    serializer_class = NsInstanceSerializer
    monitor_vnf = MonitorVnf()
    etcd_client = EtcdClient()

    def create(self, request, **kwargs):
        ns_descriptors_info = NsdInfo.objects.filter(
            nsdId=request.data['nsdId']).last()
        vnf_pkg_ids = json.loads(ns_descriptors_info.vnfPkgIds)
        nsd_info_id = str(ns_descriptors_info.id)
        request.data['nsdInfoId'] = nsd_info_id
        request.data['nsInstanceName'] = request.data['nsName']
        request.data['nsInstanceDescription'] = request.data['nsDescription']
        request.data['nsdId'] = request.data['nsdId']
        request.data['vnfInstance'] = get_vnf_instance(vnf_pkg_ids)
        request.data['_links'] = {'self': request.build_absolute_uri()}
        request.data['vnffgInfo'] = get_vnffg(nsd_info_id)

        return super().create(request)

    def get_success_headers(self, data):
        return {'Location': data['_links']['self']}

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if not_instantiated != instance.nsState:
            raise APIException(
                detail='nsState is not {}'.format(not_instantiated),
                code=status.HTTP_409_CONFLICT)

        super().destroy(request)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=True, methods=['POST'], url_path='instantiate')
    def instantiate_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if not_instantiated != ns_instance.nsState:
            raise APIException(
                detail='Network Service Instance State have been {}'.format(
                    not_instantiated),
                code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()
        vnf_instance_data = request.data.pop('vnfInstanceData')
        process_vnffg = None
        if ns_instance.NsInstance_VnffgInfo.last() is not None:
            process_vnffg = ProcessFPInstance(str(ns_instance.nsdInfoId))

        for vnf_instance_info in vnf_instance_data:
            vnf_instance = ns_instance.NsInstance_VnfInstance.get(
                id=vnf_instance_info['vnfInstanceId'])
            vnf_instance.VnfInstance_instantiatedVnfInfo.vnfState = 'STARTED'
            vnf_instance.VnfInstance_instantiatedVnfInfo.save()
            create_network_service = \
                CreateService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            create_network_service.process_instance()

            vnf_instance_list.append(vnf_instance)
            if process_vnffg:
                process_vnffg.mapping_rsp(vnf_instance.vnfdId,
                                          vnf_instance.vnfInstanceName)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list,
                          self.monitor_vnf.instantiate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'],
                                        self.monitor_vnf.instantiate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Running',
                                        usage_state=in_use)

        ns_instance.nsState = instantiated
        ns_instance.save()

        return Response(
            status=status.HTTP_202_ACCEPTED,
            headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='scale')
    def scale_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(
                detail='Network Service instance State have been INSTANTIATE')

        if 'scaleType' not in request.data:
            raise APIException(detail='scaleType parameter is necessary')

        vnf_instance_list = list()
        if 'SCALE_VNF' == request.data['scaleType']:
            for scale_vnf_data in request.data['scaleVnfData']:
                vnf_instance = ns_instance.NsInstance_VnfInstance.get(
                    id=scale_vnf_data['vnfInstanceId'])
                if 'SCALE_OUT' == scale_vnf_data['scaleVnfType']:
                    if 'additionalParams' in scale_vnf_data['scaleByStepData']:
                        additional_params = scale_vnf_data['scaleByStepData'][
                            'additionalParams']
                        replicas = int(
                            additional_params['replicas']
                        ) if 'replicas' in additional_params else None
                        virtual_mem_size = additional_params[
                            'virtual_mem_size'] if 'virtual_mem_size' in additional_params else None
                        num_virtual_cpu = additional_params[
                            'num_virtual_cpu'] if 'num_virtual_cpu' in additional_params else None
                        create_network_service = CreateService(
                            vnf_instance.vnfPkgId,
                            vnf_instance.vnfInstanceName)
                        create_network_service.process_instance(
                            replicas=replicas,
                            virtual_mem_size=virtual_mem_size,
                            num_virtual_cpu=num_virtual_cpu)
                        vnf_instance_list.append(vnf_instance)
            set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, 'SCALE')
            self.monitor_vnf.monitoring_vnf(kwargs['pk'],
                                            self.monitor_vnf.scale,
                                            vnf_instances=vnf_instance_list,
                                            container_phase='Running',
                                            ns_state=instantiated,
                                            usage_state=in_use)
            return Response(
                status=status.HTTP_202_ACCEPTED,
                headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='update')
    def update_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(
                detail='Network Service instance State have been INSTANTIATE')

        if 'updateType' not in request.data:
            raise APIException(detail='updateType parameter is necessary')

        vnf_instance_list = list()
        if request.data['updateType'] == 'ADD_VNF':
            if 'addVnfInstance' not in request.data and isinstance(
                    request.data['addVnfInstance'], list):
                raise APIException(
                    detail='Not found removeVnfInstanceId parameter')

            add_vnf_instance = request.data['addVnfInstance']
            for vnf_instance_request in add_vnf_instance:
                if 'vnfInstanceId' not in vnf_instance_request:
                    raise APIException(detail='Error parameter vnfInstanceId')

                # vnfInstanceId (nm -> vnfpkgid)
                vnf_info = get_vnf_instance(
                    [vnf_instance_request['vnfInstanceId']]).pop(0)
                vnf_instance = create_vnf_instance(vnf_info)
                ns_instance.NsInstance_VnfInstance.add(vnf_instance)
                create_network_service = CreateService(
                    vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
                create_network_service.process_instance()
                vnf_instance_list.append(vnf_instance)
        elif request.data['updateType'] == 'REMOVE_VNF':
            if 'removeVnfInstanceId' not in request.data:
                raise APIException(
                    detail='Not found removeVnfInstanceId parameter')
            vnf_instance = ns_instance.NsInstance_VnfInstance.get(
                id=request.data['removeVnfInstanceId'])
            vnf_instance.delete()
            delete_network_service = DeleteService(
                vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            delete_network_service.process_instance()
            vnf_instance_list.append(vnf_instance)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list,
                          self.monitor_vnf.update)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'],
                                        self.monitor_vnf.update,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Running',
                                        ns_state=instantiated,
                                        usage_state=in_use)
        return Response(
            status=status.HTTP_202_ACCEPTED,
            headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='terminate')
    def terminate_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if instantiated != ns_instance.nsState:
            raise APIException(
                detail='Network Service instance State have been {}'.format(
                    instantiated),
                code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()
        process_vnffg = None
        if ns_instance.NsInstance_VnffgInfo.last() is not None:
            process_vnffg = ProcessFPInstance(str(ns_instance.nsdInfoId))

        for vnf_instance in ns_instance.NsInstance_VnfInstance.all():
            vnf_instance.VnfInstance_instantiatedVnfInfo.vnfState = 'STOPPED'
            vnf_instance.VnfInstance_instantiatedVnfInfo.save()
            delete_network_service = \
                DeleteService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            delete_network_service.process_instance()
            self.etcd_client.set_deploy_name(
                instance_name=vnf_instance.vnfInstanceName.lower(),
                pod_name=None)
            self.etcd_client.release_pod_ip_address()
            vnf_instance_list.append(vnf_instance)
            if process_vnffg:
                process_vnffg.mapping_rsp(vnf_instance.vnfdId,
                                          vnf_instance.vnfInstanceName)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list,
                          self.monitor_vnf.terminate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'],
                                        self.monitor_vnf.terminate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Terminating',
                                        usage_state=not_in_use)
        ns_instance.nsState = not_instantiated
        ns_instance.save()

        if process_vnffg:
            process_vnffg.remove_vnffg()

        return Response(
            status=status.HTTP_202_ACCEPTED,
            headers={'Location': ns_instance.NsInstance_links.link_self})
Exemple #5
0
class NSLifecycleManagementViewSet(viewsets.ModelViewSet):
    queryset = NsInstance.objects.all()
    serializer_class = NsInstanceSerializer
    monitor_vnf = MonitorVnf()
    etcd_client = EtcdClient()

    def create(self, request, **kwargs):
        ns_descriptors_info = NsdInfo.objects.filter(nsdId=request.data['nsdId']).last()
        vnf_pkg_ids = json.loads(ns_descriptors_info.vnfPkgIds)
        nsd_info_id = str(ns_descriptors_info.id)
        request.data['nsdInfoId'] = nsd_info_id
        request.data['nsInstanceName'] = request.data['nsName']
        request.data['nsInstanceDescription'] = request.data['nsDescription']
        request.data['nsdId'] = request.data['nsdId']
        request.data['vnfInstance'] = get_vnf_Instance(vnf_pkg_ids)
        request.data['_links'] = {'self': request.build_absolute_uri()}
        request.data['vnffgInfo'] = get_vnffg(nsd_info_id)

        return super().create(request)

    def get_success_headers(self, data):
        return {'Location': data['_links']['self']}

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if not_instantiated != instance.nsState:
            raise APIException(detail='nsState is not {}'.format(not_instantiated),
                               code=status.HTTP_409_CONFLICT)

        super().destroy(request)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=True, methods=['POST'], url_path='instantiate')
    def instantiate_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if not_instantiated != ns_instance.nsState:
            raise APIException(detail='Network Service Instance State have been {}'.format(not_instantiated),
                               code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()
        vnf_instance_data = request.data.pop('vnfInstanceData')
        process_vnffg = None
        if ns_instance.NsInstance_VnffgInfo.last() is not None:
            process_vnffg = ProcessFPInstance(str(ns_instance.nsdInfoId))

        for vnf_instance_info in vnf_instance_data:
            vnf_instance = ns_instance.NsInstance_VnfInstance.get(id=vnf_instance_info['vnfInstanceId'])
            create_network_service = \
                CreateService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            create_network_service.process()

            vnf_instance_list.append(vnf_instance)
            if process_vnffg:
                process_vnffg.mapping_rsp(vnf_instance.vnfdId, vnf_instance.vnfInstanceName)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, self.monitor_vnf.instantiate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.instantiate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Running',
                                        usage_state=in_use)

        ns_instance.nsState = instantiated
        ns_instance.save()

        return Response(status=status.HTTP_202_ACCEPTED, headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='terminate')
    def terminate_ns(self, request, **kwargs):
        ns_instance = self.get_object()
        if instantiated != ns_instance.nsState:
            raise APIException(detail='Network Service instance State have been {}'.format(instantiated),
                               code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()
        process_vnffg = None
        if ns_instance.NsInstance_VnffgInfo.last() is not None:
            process_vnffg = ProcessFPInstance(str(ns_instance.nsdInfoId))

        for vnf_instance in ns_instance.NsInstance_VnfInstance.all():
            delete_network_service = \
                DeleteService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            delete_network_service.process()
            self.etcd_client.set_deploy_name(instance_name=vnf_instance.vnfInstanceName.lower(), pod_name=None)
            self.etcd_client.release_pod_ip_address()
            vnf_instance_list.append(vnf_instance)
            if process_vnffg:
                process_vnffg.mapping_rsp(vnf_instance.vnfdId, vnf_instance.vnfInstanceName)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, self.monitor_vnf.terminate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.terminate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Terminating',
                                        usage_state=not_in_use)
        ns_instance.nsState = not_instantiated
        ns_instance.save()

        if process_vnffg:
            process_vnffg.remove_vnffg()
        return Response(status=status.HTTP_202_ACCEPTED, headers={'Location': ns_instance.NsInstance_links.link_self})
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     # self.run_watch_event()
     self.etcd_client = EtcdClient()
class MonitorDeployment(BaseKubernetes):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # self.run_watch_event()
        self.etcd_client = EtcdClient()

    # def run_watch_event(self):
    #     threading.Thread(
    #         target=partial(self._get_deployment_event),
    #         daemon=True
    #     ).start()
    #
    #     threading.Thread(
    #         target=partial(self._get_pod_event),
    #         daemon=True
    #     ).start()

    def _get_pod_event(self, resource_version):
        if resource_version is None:
            stream = self.watch.stream(partial(self.core_v1.list_pod_for_all_namespaces), timeout_seconds=5)
        else:
            stream = self.watch.stream(partial(self.core_v1.list_pod_for_all_namespaces),
                                       resource_version=resource_version, timeout_seconds=5)

        for event in stream:
            _type = event['type']
            _metadata = event['object']['metadata']
            _status = event['object']['status']
            if 'name' not in _metadata:
                continue

            _name = _metadata['name']
            resource_version = _metadata['resourceVersion']

            _phase = _status['phase']
            if _type == 'MODIFIED' and 'deletionTimestamp' not in _metadata:
                if 'containerStatuses' in _status:
                    container_status = _status['containerStatuses']
                    for status in container_status:
                        if 'state' not in status:
                            continue

                        state = status['state']
                        if 'waiting' in state and \
                                'CrashLoopBackOff' == state['waiting']['reason']:
                            # alarm
                            self.pod_crash_event(None, _name)
                        else:
                            self.pod_status[_name] = _phase
            elif _type == 'DELETED' and _name in list(
                    self.pod_status) and 'deletionTimestamp' in _metadata:
                self.pod_crash_event(_name, None)
            else:
                self.pod_status[_name] = _phase

        return resource_version

    def pod_crash_event(self, instance_name, pod_name):
        if pod_name:
            self.pod_status.pop(pod_name)

        self.etcd_client.set_deploy_name(instance_name=instance_name, pod_name=pod_name)
        self.etcd_client.release_pod_ip_address()

    def _get_deployment_event(self, resource_version):
        if resource_version is None:
            stream = self.watch.stream(partial(self.app_v1.list_deployment_for_all_namespaces), timeout_seconds=5)
        else:
            stream = self.watch.stream(partial(self.app_v1.list_deployment_for_all_namespaces),
                                       resource_version=resource_version, timeout_seconds=5)

        for event in stream:
            _type = event['type']
            if 'name' not in event['object']['metadata']:
                continue
            _name = event['object']['metadata']['name']
            resource_version = event['object']['metadata']['resourceVersion']
            replicas = event['object']['spec']['replicas']
            if _type == 'DELETED' and _name in list(self.deployment_status):
                self.deployment_status.pop(_name)
            else:
                if _name not in list(self.deployment_status):
                    self.deployment_status[_name] = {'replicas': replicas}

        return resource_version

    def watch_specific_deployment(self, container_instance_name, _status, events):
        _queue = queue.Queue()
        threading.Thread(
            target=partial(self._get_deploy_status, _queue=_queue, events=events),
            daemon=True
        ).start()

        threading.Thread(
            target=lambda q, deploy_names, status: q.put(
                self._check_specific_deployment_status(
                    input_deployment_set=deploy_names, status=status)),
            args=(_queue, container_instance_name, _status),
            daemon=True
        ).start()

    def _check_specific_deployment_status(self, input_deployment_set, status):
        loop_count = -1
        resource_version_deployment = None
        resource_version_pod = None
        while len(input_deployment_set) != 0:
            resource_version_deployment = self._get_deployment_event(resource_version_deployment)
            resource_version_pod = self._get_pod_event(resource_version_pod)

            if loop_count < 0:
                loop_count = len(input_deployment_set) - 1

            all_deployment_key = list(self.deployment_status)
            input_specific_deployment = list(input_deployment_set)[loop_count]
            if status == 'Terminating':
                if input_specific_deployment not in all_deployment_key:
                    input_deployment_set.remove(input_specific_deployment)
            else:
                if input_specific_deployment in all_deployment_key:
                    pod_status_count = 0
                    for pod_name in list(self.pod_status):
                        if input_specific_deployment in pod_name:
                            if status == self.pod_status[pod_name]:
                                pod_status_count += 1
                    if self.deployment_status[input_specific_deployment]['replicas'] == pod_status_count:
                        input_deployment_set.remove(input_specific_deployment)

            loop_count = loop_count - 1
        return True

    def _get_deploy_status(self, _queue, events):
        while _queue.empty():
            pass
        print('success')
        [event() for event in events]
Exemple #8
0
class MonitorDeployment(BaseKubernetes):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.etcd_client = EtcdClient()
        self.alarm = AlarmEvent()
        global is_running
        if not is_running:
            threading.Thread(
                target=self._get_replica_event,
                args=(self.app_v1.list_deployment_for_all_namespaces,
                      self.deployment_status),
                daemon=True).start()
            threading.Thread(target=partial(self._get_pod_event),
                             daemon=True).start()
            threading.Thread(
                target=self._get_replica_event,
                args=
                (self.kubevirt_api.
                 list_virtual_machine_instance_replica_set_for_all_namespaces,
                 self.virtual_machine_replica_set),
                daemon=True).start()
            threading.Thread(target=partial(self._get_virtual_machine_event),
                             daemon=True).start()
        is_running = True

    def _get_replica_event(self, events, record: dict):
        while True:
            stream = self.watch.stream(partial(events), timeout_seconds=5)
            for event in stream:
                _type = event['type']
                if 'name' not in event['object']['metadata']:
                    continue

                _name = event['object']['metadata']['name']
                replicas = event['object']['spec']['replicas']
                if _name not in list(record):
                    record[_name] = {'replicas': replicas}

    def _get_virtual_machine_event(self):
        while True:
            for vmi in self.kubevirt_api.list_virtual_machine_instance_for_all_namespaces(
            ).items:
                metadata = vmi.metadata
                name = metadata.name
                deletion_timestamp = metadata.deletion_timestamp
                status = vmi.status
                phase = status.phase

                if status.conditions:
                    if 'Failed' == phase:
                        if not deletion_timestamp:
                            error_reason = None
                            error_message = None
                            type_record = list()
                            for conditions in status.conditions:
                                type_record.append(conditions.type)
                                if conditions.type != 'LiveMigratable' and conditions.type != 'Ready':
                                    error_reason = conditions.reason
                                    error_message = conditions.message
                            if 'Ready' not in type_record:
                                self.alarm.create_alarm(
                                    name, error_reason, error_message, False)
                                if name in list(self.virtual_machine_status):
                                    self.virtual_machine_status.pop(name)
                        elif name in list(self.virtual_machine_status):
                            self.virtual_machine_status.pop(name)
                    elif phase == 'Running' and name:
                        self.virtual_machine_status[name] = phase

    def _get_pod_event(self):
        while True:
            stream = self.watch.stream(partial(
                self.core_v1.list_pod_for_all_namespaces),
                                       timeout_seconds=5)

            for event in stream:
                _type = event['type']
                _metadata = event['object']['metadata']
                _status = event['object']['status']
                if 'name' not in _metadata:
                    continue

                _name = _metadata['name']
                _phase = _status['phase']
                if _phase == 'Running':
                    self.pod_status[_name] = _phase

                if _type == 'MODIFIED' and 'deletionTimestamp' not in _metadata:
                    if 'containerStatuses' in _status:
                        container_status = _status['containerStatuses']
                        for status in container_status:
                            if 'state' not in status:
                                continue

                            state = status['state']
                            if 'waiting' in state and \
                                    'CrashLoopBackOff' == state['waiting']['reason']:
                                self.alarm.create_alarm(
                                    _name, state['waiting']['reason'],
                                    state['waiting']['message'], True)
                                if _name in list(self.pod_status):
                                    self.pod_crash_event(None, _name)

                elif _type == 'DELETED' and _name in list(
                        self.pod_status) and 'deletionTimestamp' in _metadata:
                    self.pod_crash_event(_name, None)
                    self.pod_status.pop(_name)

    def pod_crash_event(self, instance_name, pod_name):
        self.etcd_client.set_deploy_name(instance_name=instance_name,
                                         pod_name=pod_name)
        self.etcd_client.release_pod_ip_address()

    def watch_specific_deployment(self, container_instance_name,
                                  vm_instance_name, _status, events):
        _queue = queue.Queue()
        # check two event
        success_count = 2
        threading.Thread(target=partial(self._get_deploy_status,
                                        _queue=_queue,
                                        events=events,
                                        success_count=success_count),
                         daemon=True).start()

        threading.Thread(target=lambda q, deployment_names, status: q.put(
            self._check_status(
                input_set=deployment_names, status=status, isContainer=True)),
                         args=(_queue, container_instance_name, _status),
                         daemon=True).start()

        threading.Thread(target=lambda q, vm_names, status: q.put(
            self._check_status(
                input_set=vm_names, status=status, isContainer=False)),
                         args=(_queue, vm_instance_name, _status),
                         daemon=True).start()

    def _check_status(self, input_set, status, isContainer):
        loop_count = -1
        while len(input_set) != 0:
            if isContainer:
                all_resource = self.deployment_status
                server_set = self.pod_status
            else:
                all_resource = self.virtual_machine_replica_set
                server_set = self.virtual_machine_status

            if loop_count < 0:
                loop_count = len(input_set) - 1

            specific_input_resource = list(input_set)[loop_count]
            if specific_input_resource in list(all_resource):
                if status == 'Terminating':
                    if not any(specific_input_resource in _
                               for _ in list(server_set)):
                        input_set.remove(specific_input_resource)
                        all_resource.pop(specific_input_resource)
                else:
                    complete_count = 0
                    for name in list(server_set):
                        if specific_input_resource in name:
                            if status == server_set[name]:
                                complete_count += 1
                    if all_resource[specific_input_resource][
                            'replicas'] == complete_count:
                        input_set.remove(specific_input_resource)

            loop_count -= 1
        return True

    def _get_deploy_status(self, _queue, events, success_count):
        while success_count:
            success_status = _queue.get()
            if success_status:
                success_count -= 1
        print('success')
        [event() for event in events]
class VirtualMachineInstance(KubernetesApi):
    serial = "ABCDFGHJIKLMNOPQRSTUVWXYZ1234567890"

    def __init__(self, *args, **kwargs):
        if 'virtual_mem_size' in kwargs and 'num_virtual_cpu' in kwargs and 'image' in kwargs:
            self.memory = kwargs['virtual_mem_size']
            self.cpu = kwargs['num_virtual_cpu']
            self.image = kwargs['image']
        self.network_name = kwargs['network_name'] if 'network_name' in kwargs else None
        self.user_name = kwargs['user_name'] if 'user_name' in kwargs else None
        self.user_public_key = kwargs['user_public_key'] if 'user_public_key' in kwargs else None
        self.config_map_mount_path = kwargs['config_map_mount_path'] if 'config_map_mount_path' in kwargs else None
        self.command = kwargs['command'] if 'command' in kwargs else None
        self.replicas = kwargs['replicas'] if 'replicas' in kwargs else None
        self.labels = kwargs['labels'] if 'labels' in kwargs and isinstance(kwargs['labels'], dict) else None
        if 'ports' in kwargs and 'name_of_service' in kwargs:
            self.name_of_service = kwargs['name_of_service']
        super().__init__(*args, **kwargs)
        self.etcd_client = EtcdClient()
        self.etcd_client.set_deploy_name(instance_name=self.instance_name, pod_name=None)

    def instance_specific_resource(self, **kwargs):
        virtual_machine_instance_match_label = {
            "app": self.name_of_service if self.name_of_service else self.instance_name}
        virtual_machine_instance_meta = self.kubevirt_client.K8sIoApimachineryPkgApisMetaV1ObjectMeta(labels=virtual_machine_instance_match_label)
        vmirs_spec = self.kubevirt_client.V1VirtualMachineInstanceReplicaSetSpec(
            replicas=self.replicas,
            selector=self.kubevirt_client.K8sIoApimachineryPkgApisMetaV1LabelSelector(match_labels=virtual_machine_instance_match_label),
            template=self.kubevirt_client.V1VirtualMachineInstanceTemplateSpec(
                spec=self._get_virtual_machine_instance_replica_set_spec(), metadata=virtual_machine_instance_meta))
        vmirs = self.kubevirt_client.V1VirtualMachineInstanceReplicaSet(
            api_version="kubevirt.io/v1alpha3", kind="VirtualMachineInstanceReplicaSet", spec=vmirs_spec)
        vmirs.metadata = self.kubevirt_client.K8sIoApimachineryPkgApisMetaV1ObjectMeta(
            name=self.instance_name, labels=virtual_machine_instance_match_label, namespace=self.namespace)
        return vmirs

    def _get_virtual_machine_instance_replica_set_spec(self):
        if isinstance(self.cpu, int):
            self.cpu = str(self.cpu)
        resource = self.kubevirt_client.V1ResourceRequirements(
            requests={'memory': self.memory, 'cpu': self.cpu})
        disks = list()
        disks.append(self.kubevirt_client.V1Disk(
            name='{}-{}'.format(self.instance_name, 'disk'),
            disk=self.kubevirt_client.V1DiskTarget(bus='virtio')))
        disks.append(self.kubevirt_client.V1Disk(
            name='{}-{}'.format(self.instance_name, 'init'),
            disk=self.kubevirt_client.V1DiskTarget(bus='virtio')))
        volumes = list()
        volumes.append(self.kubevirt_client.V1Volume(
            name='{}-{}'.format(self.instance_name, 'disk'),
            container_disk=self.kubevirt_client.V1ContainerDiskSource(image=self.image)))
        mount_script = str()
        if self.config_map_mount_path:
            for _ in self.config_map_mount_path:
                serial = self._get_serial()
                path = os.path.split(_.strip())
                disk_name = path[1].lower() if "." not in path[1] else path[1].split(".")[0].lower()
                print(disk_name)
                disks.append(self.kubevirt_client.V1Disk(
                    name=disk_name, serial=serial, disk=self.kubevirt_client.V1DiskTarget()))
                mount_script += self._mount_configmap(path=path[0], serial=serial)
                volumes.append(self.kubevirt_client.V1Volume(
                    name=disk_name,
                    config_map=self.kubevirt_client.V1ConfigMapVolumeSource(name=disk_name)))

        interface = list()
        interface.append(self.kubevirt_client.V1Interface(
            name='default', masquerade=self.kubevirt_client.V1InterfaceMasquerade()))
        networks = list()
        networks.append(self.kubevirt_client.V1Network(name='default', pod=self.kubevirt_client.V1PodNetwork()))
        if self.network_name.__len__() > 0:
            for idx, net_info in enumerate(self.network_name):
                if net_info['type'] == SR_IOV:
                    interface.append(self.kubevirt_client.V1Interface(
                        name='{}-{}'.format(self.instance_name, net_info['network_name']),
                        sriov=self.kubevirt_client.V1InterfaceSRIOV()))
                elif net_info['type'] == OVS:
                    interface.append(self.kubevirt_client.V1Interface(
                        name='{}-{}'.format(self.instance_name, net_info['network_name']),
                        bridge=self.kubevirt_client.V1InterfaceBridge()))
                networks.append(
                    self.kubevirt_client.V1Network(
                        name='{}-{}'.format(self.instance_name, net_info['network_name']),
                        multus=self.kubevirt_client.V1MultusNetwork(network_name=net_info['network_name'])))

                # TODO ovs-cni can not setting interface name
                # ubuntu default interface name (enp2s0)
                interface_name_count = idx + 2
                interface_name = 'enp{}s0'.format(interface_name_count)
                mount_script += self._multiple_interface(interface_name, net_info['ip_address'])
                # mount_script += self._multiple_interface(interface_name, self.etcd_client.get_vm_cidr())
                interface_name_count += 1
            mount_script += '/etc/init.d/networking restart\n'
        if self.command:
            for _ in self.command:
                mount_script += '{}\n'.format(_)

        volumes.append(self.kubevirt_client.V1Volume(
            name='{}-{}'.format(self.instance_name, 'init'),
            cloud_init_no_cloud=self.kubevirt_client.V1CloudInitNoCloudSource(
                user_data=self._get_user_data(mount_script))))

        devices = self.kubevirt_client.V1Devices(disks=disks, interfaces=interface)
        domain = self.kubevirt_client.V1DomainSpec(resources=resource, devices=devices)
        virtual_machine_instance_spec = self.kubevirt_client.V1VirtualMachineInstanceSpec(
            networks=networks, volumes=volumes, domain=domain, termination_grace_period_seconds=0)
        return virtual_machine_instance_spec

    def patch_resource(self, **kwargs):
        # vmi.spec.template.spec.domain.resources.requests['memory'] = '512M'
        self.kubevirt_api.replace_namespaced_virtual_machine_instance_replica_set(
            name=self.instance_name, namespace=self.namespace, body=self.resource)
        # self._restart_vmis()

    def delete_resource(self, **kwargs):
        self.kubevirt_api.delete_namespaced_virtual_machine_instance_replica_set(
            namespace=self.namespace, name=self.instance_name, body=self.kubevirt_client.K8sIoApimachineryPkgApisMetaV1DeleteOptions())

    def create_resource(self, **kwargs):
        body = self.resource
        namespace = self.namespace
        api_response = self.kubevirt_api.create_namespaced_virtual_machine_instance_replica_set(body, namespace)

    def read_resource(self, **kwargs):
        try:
            resource = self.kubevirt_api.read_namespaced_virtual_machine_instance_replica_set(
                name=self.instance_name, namespace=self.namespace)
        except self.kubevirt_client.api_client.ApiException as e:
            if e.status == 404:
                print("Exception when calling DefaultApi->read_namespaced_virtual_machine_instance_replica_set: %s\n" % e)
                return None
            raise
        return resource

    def _restart_vmis(self):
        self.kubevirt_api.restart(namespace=self.namespace, name=self.instance_name)

    def _get_serial(self):
        return ''.join(random.choice(self.serial) for _ in range(16))

    def _get_user_data(self, mount_script):
        return ('#!/bin/bash\n'
                'export NEW_USER={user_name}\n'
                'export SSH_PUB_KEY="{user_public_key}"\n'
                'sudo adduser -U -m $NEW_USER\n'
                'echo "$NEW_USER:atomic" | chpasswd\n'
                'sudo mkdir /home/$NEW_USER/.ssh\n'
                'sudo echo "$SSH_PUB_KEY" > /home/$NEW_USER/.ssh/authorized_keys\n'
                'sudo chown -R ${NEW_USER}: /home/$NEW_USER/.ssh\n'
                '{mount_script}'
                ).format(user_name=self.user_name, user_public_key=self.user_public_key, NEW_USER='******',
                         mount_script=mount_script)

    def _multiple_interface(self, interface_name, cidr):
        return ('cat << EOF >> /etc/network/interfaces.d/50-cloud-init.cfg\n'
                'auto {interface_name}\n'
                'iface {interface_name} inet static\n'
                'address {cidr} \n'
                'EOF\n'
                ).format(interface_name=interface_name, cidr=cidr)

    def _mount_configmap(self, path, serial):
        return ('sudo mkdir {config_path}\n'
                'sudo mount /dev/$(lsblk --nodeps -no name,serial | grep {serial} | cut -f1 -d " ") {config_path}\n'
                ).format(config_path=path, serial=serial)
Exemple #10
0
class NSLifecycleManagementViewSet(viewsets.ModelViewSet):
    queryset = NsInstance.objects.all()
    serializer_class = NsInstanceSerializer
    monitor_vnf = MonitorVnf()
    etcd_client = EtcdClient()
    kafka_notification = KafkaNotification('ns_instance')

    def create(self, request, **kwargs):
        """
            Create a NS instance resource.

            The POST method creates a new NS instance resource.
        """
        if 'nsdId' not in request.data:
            raise APIException(detail='nsdId is not existing',
                               code=status.HTTP_409_CONFLICT)

        if 'nsName' not in request.data:
            raise APIException(detail='nsName is not existing',
                               code=status.HTTP_409_CONFLICT)

        if 'nsDescription' not in request.data:
            raise APIException(detail='nsDescription is not existing',
                               code=status.HTTP_409_CONFLICT)

        ns_descriptors_info = NsdInfo.objects.filter(nsdId=request.data['nsdId']).last()
        if ns_descriptors_info is None:
            raise APIException(detail='nsdId is not existing',
                               code=status.HTTP_409_CONFLICT)

        vnf_pkg_Ids = json.loads(ns_descriptors_info.vnfPkgIds)
        nsd_info_id = str(ns_descriptors_info.id)
        request.data['nsdInfoId'] = nsd_info_id
        request.data['nsInstanceName'] = request.data['nsName']
        request.data['nsInstanceDescription'] = request.data['nsDescription']
        request.data['nsdId'] = request.data['nsdId']
        request.data['vnfInstance'] = get_vnf_instance(vnf_pkg_Ids)
        request.data['_links'] = {'self': request.build_absolute_uri()}

        return super().create(request)

    def get_success_headers(self, data):
        return {'Location': data['_links']['self']}

    def retrieve(self, request, *args, **kwargs):
        """
            Read an individual NS instance resource.

            The GET method retrieves information about a NS instance by reading an individual NS instance resource.
        """
        return super().retrieve(request)

    def update(self, request, *args, **kwargs):
        raise APIException(detail='Method Not Allowed',
                           code=status.HTTP_405_METHOD_NOT_ALLOWED)

    def list(self, request, *args, **kwargs):
        """
            Query multiple NS instances.

            Query NS Instances.\
            The GET method queries information about multiple NS instances. \
            This method shall support the URI query parameters, request and response data structures, \
            and response codes, as specified in the Tables 6.4.2.3.2-1 and 6.4.2.3.2-2.
        """
        return super().list(request)

    def destroy(self, request, *args, **kwargs):
        """
            Delete NS instance resource.

            Delete NS Identifier This method deletes an individual NS instance resource.
        """
        instance = self.get_object()
        if not_instantiated != instance.nsState:
            raise APIException(detail='nsState is not {}'.format(not_instantiated),
                               code=status.HTTP_409_CONFLICT)

        super().destroy(request)
        self.kafka_notification.notify(kwargs['pk'], 'NS Instance({}) had been destroy'.format(kwargs['pk']))
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=True, methods=['POST'], url_path='instantiate')
    def instantiate_ns(self, request, **kwargs):
        """
            Instantiate a NS.

            The POST method requests to instantiate a NS instance resource.
        """
        ns_instance = self.get_object()

        if 'vnfInstanceData' not in request.data:
            raise APIException(detail='vnfInstanceData is not existing',
                               code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()
        vnf_instance_data = request.data.pop('vnfInstanceData')

        for vnf_instance_info in vnf_instance_data:
            if 'vnfInstanceId' not in vnf_instance_info:
                raise APIException(detail='vnfInstanceId is not existing',
                                   code=status.HTTP_409_CONFLICT)

            vnf_instance = ns_instance.NsInstance_VnfInstance.get(id=vnf_instance_info['vnfInstanceId'])
            if vnf_instance is None:
                raise APIException(detail='vnf_instance is not existing',
                                   code=status.HTTP_409_CONFLICT)

            vnf_instance.VnfInstance_instantiatedVnfInfo.vnfState = 'STARTED'
            vnf_instance.VnfInstance_instantiatedVnfInfo.save()
            create_network_service = \
                CreateService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            threading.Thread(
                target=partial(create_network_service.process_instance),
                daemon=True
            ).start()

            vnf_instance_list.append(vnf_instance)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, self.monitor_vnf.instantiate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.instantiate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Running',
                                        ns_state=instantiated,
                                        usage_state=in_use)

        ns_instance.nsState = instantiated
        ns_instance.save()

        return Response(status=status.HTTP_202_ACCEPTED, headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='scale')
    def scale_ns(self, request, **kwargs):
        """
            Scale a NS instance.

            The POST method requests to instantiate a NS instance resource.
        """
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(detail='Network Service instance State have been INSTANTIATE')

        if 'scaleType' not in request.data:
            raise APIException(detail='scaleType parameter is necessary')

        vnf_instance_list = list()
        if 'SCALE_VNF' == request.data['scaleType']:
            for scale_vnf_data in request.data['scaleVnfData']:
                vnf_instance = ns_instance.NsInstance_VnfInstance.get(id=scale_vnf_data['vnfInstanceId'])
                if 'SCALE_OUT' == scale_vnf_data['scaleVnfType']:
                    if 'additionalParams' in scale_vnf_data['scaleByStepData']:
                        additional_params = scale_vnf_data['scaleByStepData']['additionalParams']
                        replicas = int(additional_params['replicas']) if 'replicas' in additional_params else None
                        virtual_mem_size = additional_params[
                            'virtual_mem_size'] if 'virtual_mem_size' in additional_params else None
                        num_virtual_cpu = additional_params[
                            'num_virtual_cpu'] if 'num_virtual_cpu' in additional_params else None
                        create_network_service = CreateService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
                        create_network_service.process_instance(
                            replicas=replicas, virtual_mem_size=virtual_mem_size, num_virtual_cpu=num_virtual_cpu)
                        vnf_instance_list.append(vnf_instance)
            set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, 'SCALE')
            self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.scale,
                                            vnf_instances=vnf_instance_list,
                                            container_phase='Running',
                                            ns_state=instantiated,
                                            usage_state=in_use)
            return Response(status=status.HTTP_202_ACCEPTED,
                            headers={'Location': ns_instance.NsInstance_links.link_self})

    # TODO
    @action(detail=True, methods=['POST'], url_path='heal')
    def heal_ns(self, request, **kwargs):
        """
            Heal a NS instance.

            The POST method requests to heal a NS instance resource. \
            This method shall follow the provisions specified in the Tables 6.4.7.3.1-1 and 6.4.7.3.1-2 \
            for URI query parameters, request and response data structures, and response codes.
        """
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(detail='Network Service instance State have been INSTANTIATE')

        return Response(status=status.HTTP_202_ACCEPTED,
                        headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='update')
    def update_ns(self, request, **kwargs):
        """
            Updates a NS instance.

            Scale NS instance. The POST method requests to scale a NS instance resource.
        """
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(detail='Network Service instance State have been INSTANTIATE')

        if 'updateType' not in request.data:
            raise APIException(detail='updateType parameter is necessary')

        vnf_instance_list = list()
        if request.data['updateType'] == 'ADD_VNF':
            if 'addVnfInstance' not in request.data and isinstance(request.data['addVnfInstance'], list):
                raise APIException(detail='Not found removeVnfInstanceId parameter')

            add_vnf_instance = request.data['addVnfInstance']
            for vnf_instance_request in add_vnf_instance:
                if 'vnfInstanceId' not in vnf_instance_request:
                    raise APIException(detail='Error parameter vnfInstanceId')

                # vnfInstanceId (nm -> vnfpkgid)
                vnf_info = get_vnf_instance([vnf_instance_request['vnfInstanceId']]).pop(0)
                vnf_instance = create_vnf_instance(vnf_info)
                ns_instance.NsInstance_VnfInstance.add(vnf_instance)
                create_network_service = CreateService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
                create_network_service.process_instance()
                vnf_instance_list.append(vnf_instance)
        elif request.data['updateType'] == 'REMOVE_VNF':
            if 'removeVnfInstanceId' not in request.data:
                raise APIException(detail='Not found removeVnfInstanceId parameter')
            vnf_instance = ns_instance.NsInstance_VnfInstance.get(id=request.data['removeVnfInstanceId'])
            vnf_instance.delete()
            delete_network_service = DeleteService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            delete_network_service.process_instance()
            vnf_instance_list.append(vnf_instance)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, self.monitor_vnf.update)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.update,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Running',
                                        ns_state=instantiated,
                                        usage_state=in_use)
        return Response(status=status.HTTP_202_ACCEPTED, headers={'Location': ns_instance.NsInstance_links.link_self})

    @action(detail=True, methods=['POST'], url_path='terminate')
    def terminate_ns(self, request, **kwargs):
        """
            Terminate a NS instance.

            Terminate NS task. The POST method terminates a NS instance. \
            This method can only be used with a NS instance in the INSTANTIATED state. \
            Terminating a NS instance does not delete the NS instance identifier, \
            but rather transitions the NS into the NOT_INSTANTIATED state. \
            This method shall support the URI query parameters, request and response data structures, \
            and response codes, as specified in the Tables 6.4.8.3.1-1 and 6.8.8.3.1-2.
        """
        ns_instance = self.get_object()
        if 'INSTANTIATED' != ns_instance.nsState:
            raise APIException(detail='Network Service instance State have been INSTANTIATE',
                               code=status.HTTP_409_CONFLICT)

        vnf_instance_list = list()

        for vnf_instance in ns_instance.NsInstance_VnfInstance.all():
            vnf_instance.VnfInstance_instantiatedVnfInfo.vnfState = 'STOPPED'
            vnf_instance.VnfInstance_instantiatedVnfInfo.save()
            delete_network_service = DeleteService(vnf_instance.vnfPkgId, vnf_instance.vnfInstanceName)
            threading.Thread(
                target=partial(delete_network_service.process_instance),
                daemon=True
            ).start()
            self.etcd_client.set_deploy_name(instance_name=vnf_instance.vnfInstanceName.lower(), pod_name=None)
            self.etcd_client.release_pod_ip_address()
            vnf_instance_list.append(vnf_instance)

        set_ns_lcm_op_occ(ns_instance, request, vnf_instance_list, self.monitor_vnf.terminate)
        self.monitor_vnf.monitoring_vnf(kwargs['pk'], self.monitor_vnf.terminate,
                                        vnf_instances=vnf_instance_list,
                                        container_phase='Terminating',
                                        ns_state=not_instantiated,
                                        usage_state=not_in_use)

        ns_instance.nsState = not_instantiated
        ns_instance.save()

        return Response(status=status.HTTP_202_ACCEPTED, headers={'Location': ns_instance.NsInstance_links.link_self})