예제 #1
0
class CEPPublisherConfiguration:
    """
    TODO: Extract common functionality
    """

    __instance = None
    log = LogFactory().get_log(__name__)

    @staticmethod
    def get_instance():
        """
        Singleton instance retriever
        :return: Instance
        :rtype : CEPPublisherConfiguration
        """
        if CEPPublisherConfiguration.__instance is None:
            CEPPublisherConfiguration.__instance = CEPPublisherConfiguration()

        return CEPPublisherConfiguration.__instance

    def __init__(self):
        self.enabled = False
        self.server_ip = None
        self.server_port = None
        self.admin_username = None
        self.admin_password = None
        self.cartridge_agent_config = CartridgeAgentConfiguration()

        self.read_config()

    def read_config(self):
        self.enabled = True if self.cartridge_agent_config.read_property(
            constants.CEP_PUBLISHER_ENABLED, False).strip().lower() == "true" else False
        if not self.enabled:
            CEPPublisherConfiguration.log.info("CEP Publisher disabled")
            return

        CEPPublisherConfiguration.log.info("CEP Publisher enabled")

        self.server_ip = self.cartridge_agent_config.read_property(
            constants.CEP_RECEIVER_IP, False)
        if self.server_ip is None or self.server_ip.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_RECEIVER_IP)

        self.server_port = self.cartridge_agent_config.read_property(
            constants.CEP_RECEIVER_PORT, False)
        if self.server_port is None or self.server_port.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_RECEIVER_PORT)

        self.admin_username = self.cartridge_agent_config.read_property(
            constants.CEP_SERVER_ADMIN_USERNAME, False)
        if self.admin_username is None or self.admin_username.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_SERVER_ADMIN_USERNAME)

        self.admin_password = self.cartridge_agent_config.read_property(
            constants.CEP_SERVER_ADMIN_PASSWORD, False)
        if self.admin_password is None or self.admin_password.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_SERVER_ADMIN_PASSWORD)

        CEPPublisherConfiguration.log.info("CEP Publisher configuration initialized")
예제 #2
0
class CEPPublisherConfiguration:
    """
    TODO: Extract common functionality
    """

    __instance = None
    log = LogFactory().get_log(__name__)

    @staticmethod
    def get_instance():
        """
        Singleton instance retriever
        :return: Instance
        :rtype : CEPPublisherConfiguration
        """
        if CEPPublisherConfiguration.__instance is None:
            CEPPublisherConfiguration.__instance = CEPPublisherConfiguration()

        return CEPPublisherConfiguration.__instance

    def __init__(self):
        self.enabled = False
        self.server_ip = None
        self.server_port = None
        self.admin_username = None
        self.admin_password = None
        self.cartridge_agent_config = CartridgeAgentConfiguration()

        self.read_config()

    def read_config(self):
        self.enabled = True if self.cartridge_agent_config.read_property(
            constants.CEP_PUBLISHER_ENABLED, False).strip().lower() == "true" else False
        if not self.enabled:
            CEPPublisherConfiguration.log.info("CEP Publisher disabled")
            return

        CEPPublisherConfiguration.log.info("CEP Publisher enabled")

        self.server_ip = self.cartridge_agent_config.read_property(
            constants.CEP_RECEIVER_IP, False)
        if self.server_ip is None or self.server_ip.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_RECEIVER_IP)

        self.server_port = self.cartridge_agent_config.read_property(
            constants.CEP_RECEIVER_PORT, False)
        if self.server_port is None or self.server_port.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_RECEIVER_PORT)

        self.admin_username = self.cartridge_agent_config.read_property(
            constants.CEP_SERVER_ADMIN_USERNAME, False)
        if self.admin_username is None or self.admin_username.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_SERVER_ADMIN_USERNAME)

        self.admin_password = self.cartridge_agent_config.read_property(
            constants.CEP_SERVER_ADMIN_PASSWORD, False)
        if self.admin_password is None or self.admin_password.strip() == "":
            raise RuntimeError("System property not found: " + constants.CEP_SERVER_ADMIN_PASSWORD)

        CEPPublisherConfiguration.log.info("CEP Publisher configuration initialized")
예제 #3
0
class CartridgeAgent(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

        self.__tenant_context_initialized = False
        self.__log_publish_manager = None
        self.__terminated = False
        self.__log = LogFactory().get_log(__name__)
        self.__config = CartridgeAgentConfiguration()

        mb_ip = self.__config.read_property(constants.MB_IP)
        mb_port = self.__config.read_property(constants.MB_PORT)

        self.__inst_topic_subscriber = EventSubscriber(
            constants.INSTANCE_NOTIFIER_TOPIC, mb_ip, mb_port)
        self.__tenant_topic_subscriber = EventSubscriber(
            constants.TENANT_TOPIC, mb_ip, mb_port)
        self.__app_topic_subscriber = EventSubscriber(
            constants.APPLICATION_SIGNUP, mb_ip, mb_port)
        self.__topology_event_subscriber = EventSubscriber(
            constants.TOPOLOGY_TOPIC, mb_ip, mb_port)

        self.__event_handler = EventHandler()

    def run(self):
        self.__log.info("Starting Cartridge Agent...")

        # Start topology event receiver thread
        self.register_topology_event_listeners()

        # wait until complete topology message is received to get LB IP
        self.wait_for_complete_topology()

        # wait for member initialized event
        while not self.__config.initialized:
            self.__log.debug(
                "Waiting for cartridge agent to be initialized...")
            time.sleep(1)

        # Start instance notifier listener thread
        self.register_instance_topic_listeners()

        # Start tenant event receiver thread
        self.register_tenant_event_listeners()

        # start application signup event listener
        self.register_application_signup_event_listeners()

        # Execute instance started shell script
        self.__event_handler.on_instance_started_event()

        # Publish instance started event
        cartridgeagentpublisher.publish_instance_started_event()

        # Execute start servers extension
        try:
            self.__event_handler.start_server_extension()
        except Exception as e:
            self.__log.exception("Error processing start servers event: %s" %
                                 e)

        # check if artifact management is required before publishing instance activated event
        repo_url = self.__config.repo_url
        if repo_url is None or str(repo_url).strip() == "":
            self.__log.info("No artifact repository found")
            self.__event_handler.on_instance_activated_event()
            cartridgeagentpublisher.publish_instance_activated_event()
        else:
            self.__log.info(
                "Artifact repository found, waiting for artifact updated event to checkout artifacts: [repo_url] %s",
                repo_url)

        persistence_mapping_payload = self.__config.persistence_mappings
        if persistence_mapping_payload is not None:
            self.__event_handler.volume_mount_extension(
                persistence_mapping_payload)

        # start log publishing thread
        if DataPublisherConfiguration.get_instance().enabled:
            log_file_paths = self.__config.log_file_paths
            if log_file_paths is None:
                self.__log.exception(
                    "No valid log file paths found, no logs will be published")
            else:
                self.__log_publish_manager = LogPublisherManager(
                    log_file_paths)
                self.__log_publish_manager.start()

        # run until terminated
        while not self.__terminated:
            time.sleep(1)

        if DataPublisherConfiguration.get_instance().enabled:
            self.__log_publish_manager.terminate_all_publishers()

    def terminate(self):
        """
        Allows the CartridgeAgent thread to be terminated

        :return: void
        """
        self.__terminated = True

    def register_instance_topic_listeners(self):
        self.__log.debug(
            "Starting instance notifier event message receiver thread")

        self.__inst_topic_subscriber.register_handler("ArtifactUpdatedEvent",
                                                      self.on_artifact_updated)
        self.__inst_topic_subscriber.register_handler(
            "InstanceCleanupMemberEvent", self.on_instance_cleanup_member)
        self.__inst_topic_subscriber.register_handler(
            "InstanceCleanupClusterEvent", self.on_instance_cleanup_cluster)

        self.__inst_topic_subscriber.start()
        self.__log.info(
            "Instance notifier event message receiver thread started")

        # wait till subscribed to continue
        while not self.__inst_topic_subscriber.is_subscribed():
            time.sleep(1)

    def register_topology_event_listeners(self):
        self.__log.debug("Starting topology event message receiver thread")

        self.__topology_event_subscriber.register_handler(
            "MemberActivatedEvent", self.on_member_activated)
        self.__topology_event_subscriber.register_handler(
            "MemberTerminatedEvent", self.on_member_terminated)
        self.__topology_event_subscriber.register_handler(
            "MemberSuspendedEvent", self.on_member_suspended)
        self.__topology_event_subscriber.register_handler(
            "CompleteTopologyEvent", self.on_complete_topology)
        self.__topology_event_subscriber.register_handler(
            "MemberStartedEvent", self.on_member_started)
        self.__topology_event_subscriber.register_handler(
            "MemberCreatedEvent", self.on_member_created)
        self.__topology_event_subscriber.register_handler(
            "MemberInitializedEvent", self.on_member_initialized)

        self.__topology_event_subscriber.start()
        self.__log.info("Cartridge agent topology receiver thread started")

        # wait till subscribed to continue
        while not self.__topology_event_subscriber.is_subscribed():
            time.sleep(1)

    def register_tenant_event_listeners(self):
        self.__log.debug("Starting tenant event message receiver thread")
        self.__tenant_topic_subscriber.register_handler(
            "SubscriptionDomainAddedEvent", self.on_subscription_domain_added)
        self.__tenant_topic_subscriber.register_handler(
            "SubscriptionDomainsRemovedEvent",
            self.on_subscription_domain_removed)
        self.__tenant_topic_subscriber.register_handler(
            "CompleteTenantEvent", self.on_complete_tenant)
        self.__tenant_topic_subscriber.register_handler(
            "TenantSubscribedEvent", self.on_tenant_subscribed)

        self.__tenant_topic_subscriber.start()
        self.__log.info("Tenant event message receiver thread started")

        # wait till subscribed to continue
        while not self.__tenant_topic_subscriber.is_subscribed():
            time.sleep(1)

    def register_application_signup_event_listeners(self):
        self.__log.debug(
            "Starting application signup event message receiver thread")
        self.__app_topic_subscriber.register_handler(
            "ApplicationSignUpRemovedEvent",
            self.on_application_signup_removed)

        self.__app_topic_subscriber.start()
        self.__log.info(
            "Application signup event message receiver thread started")

        # wait till subscribed to continue
        while not self.__app_topic_subscriber.is_subscribed():
            time.sleep(1)

    def on_artifact_updated(self, msg):
        event_obj = ArtifactUpdatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_artifact_updated_event(event_obj)

    def on_instance_cleanup_member(self, msg):
        member_in_payload = self.__config.member_id
        event_obj = InstanceCleanupMemberEvent.create_from_json(msg.payload)
        member_in_event = event_obj.member_id
        if member_in_payload == member_in_event:
            self.__event_handler.on_instance_cleanup_member_event()

    def on_instance_cleanup_cluster(self, msg):
        event_obj = InstanceCleanupClusterEvent.create_from_json(msg.payload)
        cluster_in_payload = self.__config.cluster_id
        cluster_in_event = event_obj.cluster_id
        instance_in_payload = self.__config.cluster_instance_id
        instance_in_event = event_obj.cluster_instance_id

        if cluster_in_event == cluster_in_payload and instance_in_payload == instance_in_event:
            self.__event_handler.on_instance_cleanup_cluster_event()

    def on_member_created(self, msg):
        self.__log.debug("Member created event received: %r" % msg.payload)

    def on_member_initialized(self, msg):
        self.__log.debug("Member initialized event received: %r" % msg.payload)

        if not TopologyContext.topology.initialized:
            return

        self.__event_handler.on_member_initialized_event()

    def on_member_activated(self, msg):
        self.__log.debug("Member activated event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberActivatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_activated_event(event_obj)

    def on_member_terminated(self, msg):
        self.__log.debug("Member terminated event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberTerminatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_terminated_event(event_obj)

    def on_member_suspended(self, msg):
        self.__log.debug("Member suspended event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberSuspendedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_suspended_event(event_obj)

    def on_complete_topology(self, msg):
        if not TopologyContext.topology.initialized:
            self.__log.debug("Complete topology event received")
            event_obj = CompleteTopologyEvent.create_from_json(msg.payload)
            TopologyContext.update(event_obj.topology)
            self.__event_handler.on_complete_topology_event(event_obj)
        else:
            self.__log.debug("Complete topology event updating task disabled")

    def on_member_started(self, msg):
        self.__log.debug("Member started event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberStartedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_started_event(event_obj)

    def on_subscription_domain_added(self, msg):
        self.__log.debug("Subscription domain added event received : %r" %
                         msg.payload)
        event_obj = SubscriptionDomainAddedEvent.create_from_json(msg.payload)
        self.__event_handler.on_subscription_domain_added_event(event_obj)

    def on_subscription_domain_removed(self, msg):
        self.__log.debug("Subscription domain removed event received : %r" %
                         msg.payload)
        event_obj = SubscriptionDomainRemovedEvent.create_from_json(
            msg.payload)
        self.__event_handler.on_subscription_domain_removed_event(event_obj)

    def on_complete_tenant(self, msg):
        if not self.__tenant_context_initialized:
            self.__log.debug("Complete tenant event received")
            event_obj = CompleteTenantEvent.create_from_json(msg.payload)
            TenantContext.update(event_obj.tenants)

            self.__event_handler.on_complete_tenant_event(event_obj)
            self.__tenant_context_initialized = True
        else:
            self.__log.debug("Complete tenant event updating task disabled")

    def on_tenant_subscribed(self, msg):
        self.__log.debug("Tenant subscribed event received: %r" % msg.payload)
        event_obj = TenantSubscribedEvent.create_from_json(msg.payload)
        self.__event_handler.on_tenant_subscribed_event(event_obj)

    def on_application_signup_removed(self, msg):
        self.__log.debug("Application signup removed event received: %r" %
                         msg.payload)
        event_obj = ApplicationSignUpRemovedEvent.create_from_json(msg.payload)
        self.__event_handler.on_application_signup_removed_event(event_obj)

    def wait_for_complete_topology(self):
        while not TopologyContext.topology.initialized:
            self.__log.info("Waiting for complete topology event...")
            time.sleep(5)
        self.__log.info("Complete topology event received")
예제 #4
0
class HealthStatisticsPublisher:
    """
    Publishes memory usage and load average to thrift server
    """
    log = LogFactory().get_log(__name__)

    def __init__(self):

        self.ports = []
        self.ports.append(CEPPublisherConfiguration.get_instance().server_port)

        self.cartridge_agent_config = CartridgeAgentConfiguration()

        cartridgeagentutils.wait_until_ports_active(
            CEPPublisherConfiguration.get_instance().server_ip,
            self.ports,
            int(self.cartridge_agent_config.read_property("port.check.timeout", critical=False)))
        cep_active = cartridgeagentutils.check_ports_active(CEPPublisherConfiguration.get_instance().server_ip, self.ports)
        if not cep_active:
            raise CEPPublisherException("CEP server not active. Health statistics publishing aborted.")

        self.stream_definition = HealthStatisticsPublisher.create_stream_definition()
        HealthStatisticsPublisher.log.debug("Stream definition created: %r" % str(self.stream_definition))
        self.publisher = ThriftPublisher(
            CEPPublisherConfiguration.get_instance().server_ip,
            CEPPublisherConfiguration.get_instance().server_port,
            CEPPublisherConfiguration.get_instance().admin_username,
            CEPPublisherConfiguration.get_instance().admin_password,
            self.stream_definition)

        HealthStatisticsPublisher.log.debug("HealthStatisticsPublisher initialized")

    @staticmethod
    def create_stream_definition():
        """
        Create a StreamDefinition for publishing to CEP
        """
        stream_def = StreamDefinition()
        stream_def.name = HealthStatisticsPublisherManager.STREAM_NAME
        stream_def.version = HealthStatisticsPublisherManager.STREAM_VERSION
        stream_def.nickname = HealthStatisticsPublisherManager.STREAM_NICKNAME
        stream_def.description = HealthStatisticsPublisherManager.STREAM_DESCRIPTION


        stream_def.add_payloaddata_attribute("cluster_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("cluster_instance_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("network_partition_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("member_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("partition_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("health_description", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("value", StreamDefinition.DOUBLE)

        return stream_def

    def publish_memory_usage(self, memory_usage):
        """
        Publishes the given memory usage value to the thrift server as a ThriftEvent
        :param float memory_usage: memory usage
        """

        event = ThriftEvent()
        event.payloadData.append(self.cartridge_agent_config.cluster_id)
        event.payloadData.append(self.cartridge_agent_config.cluster_instance_id)
        event.payloadData.append(self.cartridge_agent_config.network_partition_id)
        event.payloadData.append(self.cartridge_agent_config.member_id)
        event.payloadData.append(self.cartridge_agent_config.partition_id)
        event.payloadData.append(constants.MEMORY_CONSUMPTION)
        event.payloadData.append(memory_usage)

        HealthStatisticsPublisher.log.debug("Publishing cep event: [stream] %r [payload_data} %r [version] %r" % (self.stream_definition.name,event.payloadData, self.stream_definition.version))
        self.publisher.publish(event)

    def publish_load_average(self, load_avg):
        """
        Publishes the given load average value to the thrift server as a ThriftEvent
        :param float load_avg: load average value
        """

        event = ThriftEvent()
        event.payloadData.append(self.cartridge_agent_config.cluster_id)
        event.payloadData.append(self.cartridge_agent_config.cluster_instance_id)
        event.payloadData.append(self.cartridge_agent_config.network_partition_id)
        event.payloadData.append(self.cartridge_agent_config.member_id)
        event.payloadData.append(self.cartridge_agent_config.partition_id)
        event.payloadData.append(constants.LOAD_AVERAGE)
        event.payloadData.append(load_avg)

        HealthStatisticsPublisher.log.debug("Publishing cep event: [stream] %r [version] %r" % (self.stream_definition.name, self.stream_definition.version))
        self.publisher.publish(event)
예제 #5
0
class EventHandler:
    """
    Event execution related logic
    """

    def __init__(self):
        self.__log = LogFactory().get_log(__name__)
        self.__config = CartridgeAgentConfiguration()
        self.__plugins = {}
        """ :type dict{str: [PluginInfo]} : """
        self.__artifact_mgt_plugins = []
        self.__plugins, self.__artifact_mgt_plugins = self.initialize_plugins()
        self.__extension_executor = self.initialize_extensions()

    def on_instance_started_event(self):
        self.__log.debug("Processing instance started event...")
        # TODO: copy artifacts extension
        self.execute_event_extendables(constants.INSTANCE_STARTED_EVENT, {})

    def on_instance_activated_event(self):
        self.__log.debug("Processing instance activated event...")
        self.execute_event_extendables(constants.INSTANCE_ACTIVATED_EVENT, {})

    def on_artifact_updated_event(self, artifacts_updated_event):
        self.__log.info("Processing Artifact update event: [tenant] %s [cluster] %s [status] %s" %
                        (str(artifacts_updated_event.tenant_id),
                         artifacts_updated_event.cluster_id,
                         artifacts_updated_event.status))

        cluster_id_event = str(artifacts_updated_event.cluster_id).strip()
        cluster_id_payload = self.__config.cluster_id
        repo_url = str(artifacts_updated_event.repo_url).strip()

        if (repo_url != "") and (cluster_id_payload is not None) and (cluster_id_payload == cluster_id_event):
            local_repo_path = self.__config.app_path

            repo_password = None
            if artifacts_updated_event.repo_password is not None:
                secret = self.__config.cartridge_key
                repo_password = cartridgeagentutils.decrypt_password(artifacts_updated_event.repo_password, secret)

            repo_username = artifacts_updated_event.repo_username
            tenant_id = artifacts_updated_event.tenant_id
            is_multitenant = self.__config.is_multitenant
            commit_enabled = artifacts_updated_event.commit_enabled

            self.__log.info("Executing git checkout")

            if local_repo_path is None:
                raise GitRepositorySynchronizationException("Repository path is empty. Cannot perform Git operations.")

            # create repo object
            local_repo_path = self.get_repo_path_for_tenant(str(tenant_id), local_repo_path, is_multitenant)
            repo_info = Repository(repo_url, repo_username, repo_password, local_repo_path, tenant_id, commit_enabled)

            # checkout code
            subscribe_run, updated = AgentGitHandler.checkout(repo_info)
            # execute artifact updated extension
            plugin_values = {"ARTIFACT_UPDATED_CLUSTER_ID": artifacts_updated_event.cluster_id,
                             "ARTIFACT_UPDATED_TENANT_ID": artifacts_updated_event.tenant_id,
                             "ARTIFACT_UPDATED_REPO_URL": artifacts_updated_event.repo_url,
                             "ARTIFACT_UPDATED_REPO_PASSWORD": artifacts_updated_event.repo_password,
                             "ARTIFACT_UPDATED_REPO_USERNAME": artifacts_updated_event.repo_username,
                             "ARTIFACT_UPDATED_STATUS": artifacts_updated_event.status}

            self.execute_event_extendables(constants.ARTIFACT_UPDATED_EVENT, plugin_values)

            if subscribe_run:
                # publish instanceActivated
                cartridgeagentpublisher.publish_instance_activated_event()
            elif updated:
                # updated on pull
                self.on_artifact_update_scheduler_event(tenant_id)

            update_artifacts = self.__config.read_property(constants.ENABLE_ARTIFACT_UPDATE, False)
            update_artifacts = True if str(update_artifacts).strip().lower() == "true" else False
            if update_artifacts:
                auto_commit = self.__config.is_commits_enabled
                auto_checkout = self.__config.is_checkout_enabled

                try:
                    update_interval = int(self.__config.artifact_update_interval)
                except ValueError:
                    self.__log.exception("Invalid artifact sync interval specified.")
                    update_interval = 10

                self.__log.info("Artifact updating task enabled, update interval: %s seconds" % update_interval)

                self.__log.info("Auto Commit is turned %s " % ("on" if auto_commit else "off"))
                self.__log.info("Auto Checkout is turned %s " % ("on" if auto_checkout else "off"))

                AgentGitHandler.schedule_artifact_update_task(
                    repo_info,
                    auto_checkout,
                    auto_commit,
                    update_interval)

    def on_artifact_update_scheduler_event(self, tenant_id):
        self.__log.info("Processing Artifact update scheduler event...")
        plugin_values = {"ARTIFACT_UPDATED_TENANT_ID": str(tenant_id),
                         "ARTIFACT_UPDATED_SCHEDULER": str(True)}

        self.execute_event_extendables("ArtifactUpdateSchedulerEvent", plugin_values)

    def on_instance_cleanup_cluster_event(self):
        self.__log.info("Processing instance cleanup cluster event...")
        self.cleanup(constants.INSTANCE_CLEANUP_CLUSTER_EVENT)

    def on_instance_cleanup_member_event(self):
        self.__log.info("Processing instance cleanup member event...")
        self.cleanup(constants.INSTANCE_CLEANUP_MEMBER_EVENT)

    def on_member_activated_event(self, member_activated_event):
        self.__log.info("Processing Member activated event: [service] %r [cluster] %r [member] %r"
                        % (member_activated_event.service_name,
                           member_activated_event.cluster_id,
                           member_activated_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_activated_event.service_name,
            member_activated_event.cluster_id,
            member_activated_event.member_id)

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member activated event")
            return

        self.execute_event_extendables(constants.MEMBER_ACTIVATED_EVENT, {})

    def on_complete_topology_event(self, complete_topology_event):
        self.__log.debug("Processing Complete topology event...")

        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_initialized = self.check_member_state_in_topology(
            service_name_in_payload,
            cluster_id_in_payload,
            member_id_in_payload)

        self.__log.debug("Member initialized %s", member_initialized)
        if member_initialized:
            # Set cartridge agent as initialized since member is available and it is in initialized state
            self.__config.initialized = True

        topology = complete_topology_event.get_topology()
        service = topology.get_service(service_name_in_payload)
        cluster = service.get_cluster(cluster_id_in_payload)

        plugin_values = {"TOPOLOGY_JSON": json.dumps(topology.json_str),
                         "MEMBER_LIST_JSON": json.dumps(cluster.member_list_json)}

        self.execute_event_extendables(constants.COMPLETE_TOPOLOGY_EVENT, plugin_values)

    def on_member_initialized_event(self):
        """
         Member initialized event is sent by cloud controller once volume attachment and
         ip address allocation is completed successfully
        :return:
        """
        self.__log.debug("Processing Member initialized event...")

        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_exists = self.member_exists_in_topology(service_name_in_payload, cluster_id_in_payload,
                                                       member_id_in_payload)

        self.__log.debug("Member exists: %s" % member_exists)

        if member_exists:
            self.__config.initialized = True

        self.execute_event_extendables(constants.MEMBER_INITIALIZED_EVENT, {})

    def on_complete_tenant_event(self, complete_tenant_event):
        self.__log.debug("Processing Complete tenant event...")

        tenant_list_json = complete_tenant_event.tenant_list_json
        self.__log.debug("Complete tenants:" + json.dumps(tenant_list_json))

        plugin_values = {"TENANT_LIST_JSON": json.dumps(tenant_list_json)}

        self.execute_event_extendables(constants.COMPLETE_TENANT_EVENT, plugin_values)

    def on_member_terminated_event(self, member_terminated_event):
        self.__log.info("Processing Member terminated event: [service] %s [cluster] %s [member] %s" %
                        (member_terminated_event.service_name, member_terminated_event.cluster_id,
                         member_terminated_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_terminated_event.service_name,
            member_terminated_event.cluster_id,
            member_terminated_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member terminated event")
            return

        self.execute_event_extendables(constants.MEMBER_TERMINATED_EVENT, {})

    def on_member_suspended_event(self, member_suspended_event):
        self.__log.info("Processing Member suspended event: [service] %s [cluster] %s [member] %s" %
                        (member_suspended_event.service_name, member_suspended_event.cluster_id,
                         member_suspended_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_suspended_event.service_name,
            member_suspended_event.cluster_id,
            member_suspended_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member suspended event")
            return

        self.execute_event_extendables(constants.MEMBER_SUSPENDED_EVENT, {})

    def on_member_started_event(self, member_started_event):
        self.__log.info("Processing Member started event: [service] %s [cluster] %s [member] %s" %
                        (member_started_event.service_name, member_started_event.cluster_id,
                         member_started_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_started_event.service_name,
            member_started_event.cluster_id,
            member_started_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member started event")
            return

        self.execute_event_extendables(constants.MEMBER_STARTED_EVENT, {})

    def start_server_extension(self):
        self.__log.info("Processing start server extension...")
        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_initialized = self.check_member_state_in_topology(service_name_in_payload, cluster_id_in_payload,
                                                                 member_id_in_payload)

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute start server event")
            return

        self.execute_event_extendables("StartServers", {})

    def volume_mount_extension(self, persistence_mappings_payload):
        self.__log.info("Processing volume mount extension...")
        self.execute_event_extendables("VolumeMount", persistence_mappings_payload)

    def on_domain_mapping_added_event(self, domain_mapping_added_event):
        tenant_domain = EventHandler.find_tenant_domain(domain_mapping_added_event.tenant_id)
        self.__log.info(
            "Processing Domain mapping added event: [tenant-id] " + str(domain_mapping_added_event.tenant_id) +
            " [tenant-domain] " + tenant_domain + " [domain-name] " + domain_mapping_added_event.domain_name +
            " [application-context] " + domain_mapping_added_event.application_context
        )

        plugin_values = {"SUBSCRIPTION_APPLICATION_ID": domain_mapping_added_event.application_id,
                         "SUBSCRIPTION_SERVICE_NAME": domain_mapping_added_event.service_name,
                         "SUBSCRIPTION_DOMAIN_NAME": domain_mapping_added_event.domain_name,
                         "SUBSCRIPTION_CLUSTER_ID": domain_mapping_added_event.cluster_id,
                         "SUBSCRIPTION_TENANT_ID": int(domain_mapping_added_event.tenant_id),
                         "SUBSCRIPTION_TENANT_DOMAIN": tenant_domain,
                         "SUBSCRIPTION_CONTEXT_PATH":
                             domain_mapping_added_event.context_path}

        self.execute_event_extendables(constants.DOMAIN_MAPPING_ADDED_EVENT, plugin_values)

    def on_domain_mapping_removed_event(self, domain_mapping_removed_event):
        tenant_domain = EventHandler.find_tenant_domain(domain_mapping_removed_event.tenant_id)
        self.__log.info(
            "Domain mapping removed event received: [tenant-id] " + str(domain_mapping_removed_event.tenant_id) +
            " [tenant-domain] " + tenant_domain + " [domain-name] " + domain_mapping_removed_event.domain_name
        )

        plugin_values = {"SUBSCRIPTION_APPLICATION_ID": domain_mapping_removed_event.application_id,
                         "SUBSCRIPTION_SERVICE_NAME": domain_mapping_removed_event.service_name,
                         "SUBSCRIPTION_DOMAIN_NAME": domain_mapping_removed_event.domain_name,
                         "SUBSCRIPTION_CLUSTER_ID": domain_mapping_removed_event.cluster_id,
                         "SUBSCRIPTION_TENANT_ID": int(domain_mapping_removed_event.tenant_id),
                         "SUBSCRIPTION_TENANT_DOMAIN": tenant_domain}

        self.execute_event_extendables(constants.DOMAIN_MAPPING_REMOVED_EVENT, plugin_values)

    def on_copy_artifacts_extension(self, src, dest):
        self.__log.info("Processing Copy artifacts extension...")
        plugin_values = {"SOURCE": src, "DEST": dest}
        self.execute_event_extendables("CopyArtifacts", plugin_values)

    def on_tenant_subscribed_event(self, tenant_subscribed_event):
        self.__log.info(
            "Processing Tenant subscribed event: [tenant] " + str(tenant_subscribed_event.tenant_id) +
            " [service] " + tenant_subscribed_event.service_name + " [cluster] " + tenant_subscribed_event.cluster_ids
        )

        self.execute_event_extendables(constants.TENANT_SUBSCRIBED_EVENT, {})

    def on_application_signup_removed_event(self, application_signup_removal_event):
        self.__log.info(
            "Processing Tenant unsubscribed event: [tenant] " + str(application_signup_removal_event.tenantId) +
            " [application ID] " + str(application_signup_removal_event.applicationId)
        )

        if self.__config.application_id == application_signup_removal_event.applicationId:
            AgentGitHandler.remove_repo(application_signup_removal_event.tenantId)

        self.execute_event_extendables(constants.APPLICATION_SIGNUP_REMOVAL_EVENT, {})

    def cleanup(self, event):
        self.__log.info("Executing cleaning up the data in the cartridge instance...")

        cartridgeagentpublisher.publish_maintenance_mode_event()

        self.execute_event_extendables("clean", {})
        self.__log.info("cleaning up finished in the cartridge instance...")

        self.__log.info("publishing ready to shutdown event...")
        cartridgeagentpublisher.publish_instance_ready_to_shutdown_event()

    def initialize_plugins(self):
        """ Find, load, activate and group plugins for Python CA
        :return: a tuple of (PluginManager, plugins, artifact management plugins)
        """
        self.__log.info("Collecting and loading plugins")

        try:
            # TODO: change plugin descriptor ext, plugin_manager.setPluginInfoExtension(AGENT_PLUGIN_EXT)
            plugins_dir = self.__config.read_property(constants.PLUGINS_DIR)
            category_filter = {CARTRIDGE_AGENT_PLUGIN: ICartridgeAgentPlugin, ARTIFACT_MGT_PLUGIN: IArtifactManagementPlugin}

            plugin_manager = EventHandler.create_plugin_manager(category_filter, plugins_dir)

            # activate cartridge agent plugins
            plugins = plugin_manager.getPluginsOfCategory(CARTRIDGE_AGENT_PLUGIN)
            grouped_plugins = {}
            for plugin_info in plugins:
                self.__log.debug("Found plugin [%s] at [%s]" % (plugin_info.name, plugin_info.path))
                plugin_manager.activatePluginByName(plugin_info.name)
                self.__log.info("Activated plugin [%s]" % plugin_info.name)

                mapped_events = plugin_info.description.split(",")
                for mapped_event in mapped_events:
                    if mapped_event.strip() != "":
                        if grouped_plugins.get(mapped_event) is None:
                            grouped_plugins[mapped_event] = []

                        grouped_plugins[mapped_event].append(plugin_info)

            # activate artifact management plugins
            artifact_mgt_plugins = plugin_manager.getPluginsOfCategory(ARTIFACT_MGT_PLUGIN)
            for plugin_info in artifact_mgt_plugins:
                self.__log.debug("Found artifact management plugin [%s] at [%s]" % (plugin_info.name, plugin_info.path))
                plugin_manager.activatePluginByName(plugin_info.name)
                self.__log.info("Activated artifact management plugin [%s]" % plugin_info.name)

            return grouped_plugins, artifact_mgt_plugins
        except ParameterNotFoundException as e:
            self.__log.exception("Could not load plugins. Plugins directory not set: %s" % e)
            return None, None
        except Exception as e:
            self.__log.exception("Error while loading plugin: %s" % e)
            return None, None

    def initialize_extensions(self):
        """ Find, load and activate extension scripts for Python CA. The extensions are mapped to the event by the
        name used in the plugin descriptor.
        :return:a tuple of (PluginManager, extensions)
        """
        self.__log.info("Collecting and loading extensions")

        try:
            extensions_dir = self.__config.read_property(constants.EXTENSIONS_DIR)
            category_filter = {CARTRIDGE_AGENT_PLUGIN: ICartridgeAgentPlugin}

            extension_manager = EventHandler.create_plugin_manager(category_filter, extensions_dir)

            all_extensions = extension_manager.getPluginsOfCategory(CARTRIDGE_AGENT_PLUGIN)
            for plugin_info in all_extensions:
                try:
                    self.__log.debug("Found extension executor [%s] at [%s]" % (plugin_info.name, plugin_info.path))
                    extension_manager.activatePluginByName(plugin_info.name)
                    extension_executor = plugin_info
                    self.__log.info("Activated extension executor [%s]" % plugin_info.name)
                    # extension executor found. break loop and return
                    return extension_executor
                except Exception as ignored:
                    pass

            # no extension executor plugin could be loaded or activated
            raise RuntimeError("Couldn't activated any ExtensionExecutor plugin")
        except ParameterNotFoundException as e:
            self.__log.exception("Could not load extensions. Extensions directory not set: %s" % e)
            return None
        except Exception as e:
            self.__log.exception("Error while loading extension: %s" % e)
            return None

    @staticmethod
    def create_plugin_manager(category_filter, plugin_place):
        """ Creates a PluginManager object from the given folder according to the given filter
        :param category_filter:
        :param plugin_place:
        :return:
        :rtype: PluginManager
        """
        plugin_manager = PluginManager()
        plugin_manager.setCategoriesFilter(category_filter)
        plugin_manager.setPluginPlaces([plugin_place])

        plugin_manager.collectPlugins()

        return plugin_manager

    def execute_event_extendables(self, event, input_values):
        """ Execute the extensions and plugins related to the event
        :param event: The event name string
        :param input_values: the values to be passed to the plugin
        :return:
        """
        try:
            input_values = self.add_common_input_values(input_values)
            input_values["EVENT"] = event
        except Exception as e:
            self.__log.error("Error while adding common input values for event extendables: %s" % e)

        # Execute the extension
        self.execute_extension_for_event(event, input_values)
        # Execute the plugins
        self.execute_plugins_for_event(event, input_values)

    def execute_plugins_for_event(self, event, input_values):
        """ For each plugin registered for the specified event, start a plugin execution thread
       :param str event: The event name string
       :param dict input_values: the values to be passed to the plugin
       :return:
       """
        try:
            plugins_for_event = self.__plugins.get(event)
            if plugins_for_event is not None:
                for plugin_info in plugins_for_event:
                    self.__log.debug("Executing plugin %s for event %s" % (plugin_info.name, event))
                    plugin_thread = PluginExecutor(plugin_info, input_values)
                    plugin_thread.start()

                    # block till plugin run completes.
                    plugin_thread.join()
            else:
                self.__log.debug("No plugins registered for event %s" % event)
        except Exception as e:
            self.__log.exception("Error while executing plugin for event %s: %s" % (event, e))

    def execute_extension_for_event(self, event, extension_values):
        """ Execute the extension related to the event
        :param event: The event name string
        :param extension_values: the values to be passed to the plugin
        :return:
        """
        try:
            if self.__extension_executor is not None:
                self.__log.debug("Executing extension for event [%s]" % event)
                PluginExecutor(self.__extension_executor, extension_values).start()
                extension_thread = PluginExecutor(self.__extension_executor, extension_values)
                extension_thread.start()

                # block till plugin run completes.
                extension_thread.join()
            else:
                self.__log.debug("No extensions registered for event %s" % event)
        except OSError:
            self.__log.warn("No extension was found for event %s" % event)
        except Exception as e:
            self.__log.exception("Error while executing extension for event %s: %s" % (event, e))

    def get_repo_path_for_tenant(self, tenant_id, git_local_repo_path, is_multitenant):
        """ Finds the repository path for tenant to clone from the remote repository
        :param tenant_id:
        :param git_local_repo_path:
        :param is_multitenant:
        :return:
        """
        repo_path = ""

        if is_multitenant:
            if tenant_id == SUPER_TENANT_ID:
                # super tenant, /repository/deploy/server/
                super_tenant_repo_path = self.__config.super_tenant_repository_path
                # "app_path"
                repo_path += git_local_repo_path

                if super_tenant_repo_path is not None and super_tenant_repo_path != "":
                    super_tenant_repo_path = super_tenant_repo_path if super_tenant_repo_path.startswith("/") \
                        else "/" + super_tenant_repo_path
                    super_tenant_repo_path = super_tenant_repo_path if super_tenant_repo_path.endswith("/") \
                        else super_tenant_repo_path + "/"
                    # "app_path/repository/deploy/server/"
                    repo_path += super_tenant_repo_path
                else:
                    # "app_path/repository/deploy/server/"
                    repo_path += SUPER_TENANT_REPO_PATH

            else:
                # normal tenant, /repository/tenants/tenant_id
                tenant_repo_path = self.__config.tenant_repository_path
                # "app_path"
                repo_path += git_local_repo_path

                if tenant_repo_path is not None and tenant_repo_path != "":
                    tenant_repo_path = tenant_repo_path if tenant_repo_path.startswith("/") else "/" + tenant_repo_path
                    tenant_repo_path = tenant_repo_path if tenant_repo_path.endswith("/") else tenant_repo_path + "/"
                    # "app_path/repository/tenants/244653444"
                    repo_path += tenant_repo_path + tenant_id
                else:
                    # "app_path/repository/tenants/244653444"
                    repo_path += TENANT_REPO_PATH + tenant_id

                    # tenant_dir_path = git_local_repo_path + AgentGitHandler.TENANT_REPO_PATH + tenant_id
                    # GitUtils.create_dir(repo_path)
        else:
            # not multi tenant, app_path
            repo_path = git_local_repo_path

        self.__log.debug("Repo path returned : %r" % repo_path)
        return repo_path

    def check_member_state_in_topology(self, service_name, cluster_id, member_id):
        topology = TopologyContext.get_topology()
        service = topology.get_service(service_name)
        if service is None:
            self.__log.error("Service not found in topology [service] %s" % service_name)
            return False

        cluster = service.get_cluster(cluster_id)
        if cluster is None:
            self.__log.error("Cluster id not found in topology [cluster] %s" % cluster_id)
            return False

        activated_member = cluster.get_member(member_id)
        if activated_member is None:
            self.__log.error("Member id not found in topology [member] %s" % member_id)
            return False

        if activated_member.status != MemberStatus.Initialized:
            return False

        return True

    def member_exists_in_topology(self, service_name, cluster_id, member_id):
        topology = TopologyContext.get_topology()
        service = topology.get_service(service_name)
        if service is None:
            self.__log.error("Service not found in topology [service] %s" % service_name)
            return False

        cluster = service.get_cluster(cluster_id)
        if cluster is None:
            self.__log.error("Cluster id not found in topology [cluster] %s" % cluster_id)
            return False

        activated_member = cluster.get_member(member_id)
        if activated_member is None:
            self.__log.error("Member id not found in topology [member] %s" % member_id)
            return False

        return True

    def add_common_input_values(self, plugin_values):
        """
        Adds the common parameters to be used by the extension scripts
        :param dict[str, str] plugin_values: Dictionary to be added
        :return: Dictionary with updated parameters
        :rtype: dict[str, str]
        """
        if plugin_values is None:
            plugin_values = {}
        elif type(plugin_values) != dict:
            plugin_values = {"VALUE1": str(plugin_values)}

        plugin_values["APPLICATION_PATH"] = self.__config.app_path
        plugin_values["PARAM_FILE_PATH"] = self.__config.read_property(constants.PARAM_FILE_PATH, False)
        plugin_values["PERSISTENCE_MAPPINGS"] = self.__config.persistence_mappings

        lb_cluster_id_in_payload = self.__config.lb_cluster_id
        lb_private_ip, lb_public_ip = EventHandler.get_lb_member_ip(lb_cluster_id_in_payload)
        plugin_values["LB_IP"] = lb_private_ip if lb_private_ip is not None else self.__config.lb_private_ip
        plugin_values["LB_PUBLIC_IP"] = lb_public_ip if lb_public_ip is not None else self.__config.lb_public_ip

        topology = TopologyContext.get_topology()
        if topology.initialized:
            service = topology.get_service(self.__config.service_name)
            cluster = service.get_cluster(self.__config.cluster_id)
            member_id_in_payload = self.__config.member_id
            member = cluster.get_member(member_id_in_payload)
            EventHandler.add_properties(service.properties, plugin_values, "SERVICE_PROPERTY")
            EventHandler.add_properties(cluster.properties, plugin_values, "CLUSTER_PROPERTY")
            EventHandler.add_properties(member.properties, plugin_values, "MEMBER_PROPERTY")

        plugin_values.update(self.__config.get_payload_params())

        return EventHandler.clean_process_parameters(plugin_values)

    @staticmethod
    def add_properties(properties, params, prefix):
        """
        Adds the given property list to the parameters list with given prefix in the parameter name
        :param dict[str, str] properties: service properties
        :param dict[str, str] params:
        :param str prefix:
        :return: dict[str, str]
        """
        if properties is None or properties.items() is None:
            return

        for key in properties:
            params[prefix + "_" + key] = str(properties[key])

    @staticmethod
    def get_lb_member_ip(lb_cluster_id):
        topology = TopologyContext.get_topology()
        services = topology.get_services()

        for service in services:
            clusters = service.get_clusters()
            for cluster in clusters:
                members = cluster.get_members()
                for member in members:
                    if member.cluster_id == lb_cluster_id:
                        return member.member_default_private_ip, member.member_default_public_ip

        return None, None

    @staticmethod
    def clean_process_parameters(params):
        """
        Removes any null valued parameters before passing them to the extension scripts
        :param dict params:
        :return: cleaned parameters
        :rtype: dict
        """
        for key, value in params.items():
            if value is None:
                del params[key]

        return params

    @staticmethod
    def find_tenant_domain(tenant_id):
        tenant = TenantContext.get_tenant(tenant_id)
        if tenant is None:
            raise RuntimeError("Tenant could not be found: [tenant-id] %s" % str(tenant_id))

        return tenant.tenant_domain
예제 #6
0
# "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 urllib2, urllib
from urllib2 import URLError, HTTPError
import json
from modules.util.log import LogFactory
from config import CartridgeAgentConfiguration
import constants


log = LogFactory().get_log(__name__)
config = CartridgeAgentConfiguration()
mds_url = config.read_property(constants.METADATA_SERVICE_URL)
alias = config.read_property(constants.CARTRIDGE_ALIAS)
app_id = config.read_property(constants.APPLICATION_ID)
token = config.read_property(constants.TOKEN)
alias_resource_url = mds_url + "/metadata/api/application/" + app_id + "/cluster/" + alias + "/properties"
app_resource_url = mds_url + "/metadata/api/application/" + app_id + "/properties"


def put(put_req, app=False):
    """ Publish a set of key values to the metadata service
    :param MDSPutRequest put_req:
    :param
    :return: the response string or None if exception
    :rtype: str
    """
    # serialize put request object to json
예제 #7
0
class LogPublisherManager(Thread):
    """
    A log publishing thread management thread which maintains a log publisher for each log file. Also defines a stream
    definition and the BAM/CEP server information for a single publishing context.
    """

    @staticmethod
    def define_stream(tenant_id, alias, date_time):
        """
        Creates a stream definition for Log Publishing
        :return: A StreamDefinition object with the required attributes added
        :rtype : StreamDefinition
        """
        # stream definition
        stream_definition = StreamDefinition()
        stream_name = "logs." + tenant_id + "." \
                      + alias + "." + date_time
        stream_version = "1.0.0"
        stream_nickname = "log entries from instance"
        stream_description = "Apache Stratos Instance Log Publisher"

        stream_definition.name = stream_name
        stream_definition.version = stream_version
        stream_definition.description = stream_description
        stream_definition.nickname = stream_nickname
        stream_definition.add_metadata_attribute("memberId", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("tenantID", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("serverName", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("appName", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("logTime", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("priority", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("message", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("logger", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("ip", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("instance", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("stacktrace", StreamDefinition.STRING)

        return stream_definition

    def __init__(self, logfile_paths):
        Thread.__init__(self)

        self.log = LogFactory().get_log(__name__)

        self.logfile_paths = logfile_paths
        self.publishers = {}
        self.ports = []
        self.ports.append(DataPublisherConfiguration.get_instance().monitoring_server_port)
        self.ports.append(DataPublisherConfiguration.get_instance().monitoring_server_secure_port)

        self.cartridge_agent_config = CartridgeAgentConfiguration()

        self.log.debug("Checking if Monitoring server is active.")
        ports_active = cartridgeagentutils.wait_until_ports_active(
            DataPublisherConfiguration.get_instance().monitoring_server_ip,
            self.ports,
            int(self.cartridge_agent_config.read_property("port.check.timeout", critical=False)))

        if not ports_active:
            self.log.debug("Monitoring server is not active")
            raise DataPublisherException("Monitoring server not active, data publishing is aborted")

        self.log.debug("Monitoring server is up and running. Log Publisher Manager started.")

        self.tenant_id = LogPublisherManager.get_valid_tenant_id(CartridgeAgentConfiguration().tenant_id)
        self.alias = LogPublisherManager.get_alias(CartridgeAgentConfiguration().cluster_id)
        self.date_time = LogPublisherManager.get_current_date()

        self.stream_definition = self.define_stream(self.tenant_id, self.alias, self.date_time)

    def run(self):
        if self.logfile_paths is not None and len(self.logfile_paths):
            for log_path in self.logfile_paths:
                # thread for each log file
                publisher = self.get_publisher(log_path)
                publisher.start()
                self.log.debug("Log publisher for path \"%s\" started." % log_path)

    def get_publisher(self, log_path):
        """
        Retrieve the publisher for the specified log file path. Creates a new LogPublisher if one is not available
        :return: The LogPublisher object
        :rtype : LogPublisher
        """
        if log_path not in self.publishers:
            self.log.debug("Creating a Log publisher for path \"%s\"" % log_path)
            self.publishers[log_path] = LogPublisher(
                log_path,
                self.stream_definition,
                self.tenant_id,
                self.alias,
                self.date_time,
                self.cartridge_agent_config.member_id)

        return self.publishers[log_path]

    def terminate_publisher(self, log_path):
        """
        Terminates the LogPublisher thread associated with the specified log file
        """
        if log_path in self.publishers:
            self.publishers[log_path].terminate()

    def terminate_all_publishers(self):
        """
        Terminates all LogPublisher threads
        """
        for publisher in self.publishers:
            publisher.terminate()

    @staticmethod
    def get_valid_tenant_id(tenant_id):
        if tenant_id == constants.INVALID_TENANT_ID or tenant_id == constants.SUPER_TENANT_ID:
            return "0"

        return tenant_id

    @staticmethod
    def get_alias(cluster_id):
        try:
            alias = cluster_id.split("\\.")[0]
        except:
            alias = cluster_id

        return alias

    @staticmethod
    def get_current_date():
        """
        Returns the current date formatted as yyyy-MM-dd
        :return: Formatted date string
        :rtype : str
        """
        return datetime.date.today().strftime(constants.DATE_FORMAT)
예제 #8
0
class DataPublisherConfiguration:
    """
    A singleton implementation to access configuration information for data publishing to BAM/CEP
    TODO: perfect singleton impl ex: Borg
    """

    __instance = None
    log = LogFactory().get_log(__name__)

    @staticmethod
    def get_instance():
        """
        Singleton instance retriever
        :return: Instance
        :rtype : DataPublisherConfiguration
        """
        if DataPublisherConfiguration.__instance is None:
            DataPublisherConfiguration.__instance = DataPublisherConfiguration()

        return DataPublisherConfiguration.__instance

    def __init__(self):
        self.enabled = False
        self.monitoring_server_ip = None
        self.monitoring_server_port = None
        self.monitoring_server_secure_port = None
        self.admin_username = None
        self.admin_password = None
        self.cartridge_agent_config = CartridgeAgentConfiguration()

        self.read_config()

    def read_config(self):
        self.enabled = True if \
            self.cartridge_agent_config.read_property(constants.MONITORING_PUBLISHER_ENABLED, False).strip().lower() \
            == "true" \
            else False

        if not self.enabled:
            DataPublisherConfiguration.log.info("Data Publisher disabled")
            return

        DataPublisherConfiguration.log.info("Data Publisher enabled")

        self.monitoring_server_ip = self.cartridge_agent_config.read_property(constants.MONITORING_RECEIVER_IP, False)
        if self.monitoring_server_ip is None or self.monitoring_server_ip.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_RECEIVER_IP)

        self.monitoring_server_port = self.cartridge_agent_config.read_property(
            constants.MONITORING_RECEIVER_PORT,
            False)

        if self.monitoring_server_port is None or self.monitoring_server_port.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_RECEIVER_PORT)

        self.monitoring_server_secure_port = self.cartridge_agent_config.read_property(
            "monitoring.server.secure.port",
            False)

        if self.monitoring_server_secure_port is None or self.monitoring_server_secure_port.strip() == "":
            raise RuntimeError("System property not found: monitoring.server.secure.port")

        self.admin_username = self.cartridge_agent_config.read_property(
            constants.MONITORING_SERVER_ADMIN_USERNAME,
            False)

        if self.admin_username is None or self.admin_username.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_SERVER_ADMIN_USERNAME)

        self.admin_password = self.cartridge_agent_config.read_property(
            constants.MONITORING_SERVER_ADMIN_PASSWORD,
            False)

        if self.admin_password is None or self.admin_password.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_SERVER_ADMIN_PASSWORD)

        DataPublisherConfiguration.log.info("Data Publisher configuration initialized")
예제 #9
0
class HealthStatisticsPublisher:
    """
    Publishes memory usage and load average to thrift server
    """
    log = LogFactory().get_log(__name__)

    def __init__(self):

        self.ports = []
        self.ports.append(CEPPublisherConfiguration.get_instance().server_port)

        self.cartridge_agent_config = CartridgeAgentConfiguration()

        cartridgeagentutils.wait_until_ports_active(
            CEPPublisherConfiguration.get_instance().server_ip,
            self.ports,
            int(self.cartridge_agent_config.read_property("port.check.timeout", critical=False)))
        cep_active = cartridgeagentutils.check_ports_active(CEPPublisherConfiguration.get_instance().server_ip, self.ports)
        if not cep_active:
            raise CEPPublisherException("CEP server not active. Health statistics publishing aborted.")

        self.stream_definition = HealthStatisticsPublisher.create_stream_definition()
        HealthStatisticsPublisher.log.debug("Stream definition created: %r" % str(self.stream_definition))
        self.publisher = ThriftPublisher(
            CEPPublisherConfiguration.get_instance().server_ip,
            CEPPublisherConfiguration.get_instance().server_port,
            CEPPublisherConfiguration.get_instance().admin_username,
            CEPPublisherConfiguration.get_instance().admin_password,
            self.stream_definition)

        HealthStatisticsPublisher.log.debug("HealthStatisticsPublisher initialized")

    @staticmethod
    def create_stream_definition():
        """
        Create a StreamDefinition for publishing to CEP
        """
        stream_def = StreamDefinition()
        stream_def.name = HealthStatisticsPublisherManager.STREAM_NAME
        stream_def.version = HealthStatisticsPublisherManager.STREAM_VERSION
        stream_def.nickname = HealthStatisticsPublisherManager.STREAM_NICKNAME
        stream_def.description = HealthStatisticsPublisherManager.STREAM_DESCRIPTION

        # stream_def.add_payloaddata_attribute()
        stream_def.add_payloaddata_attribute("cluster_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("cluster_instance_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("network_partition_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("member_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("partition_id", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("health_description", StreamDefinition.STRING)
        stream_def.add_payloaddata_attribute("value", StreamDefinition.DOUBLE)

        return stream_def

    def publish_memory_usage(self, memory_usage):
        """
        Publishes the given memory usage value to the thrift server as a ThriftEvent
        :param float memory_usage: memory usage
        """

        event = ThriftEvent()
        event.payloadData.append(self.cartridge_agent_config.cluster_id)
        event.payloadData.append(self.cartridge_agent_config.cluster_instance_id)
        event.payloadData.append(self.cartridge_agent_config.network_partition_id)
        event.payloadData.append(self.cartridge_agent_config.member_id)
        event.payloadData.append(self.cartridge_agent_config.partition_id)
        event.payloadData.append(constants.MEMORY_CONSUMPTION)
        event.payloadData.append(float(memory_usage))

        HealthStatisticsPublisher.log.debug("Publishing cep event: [stream] %r [payload_data} %r [version] %r" % (self.stream_definition.name,event.payloadData, self.stream_definition.version))
        self.publisher.publish(event)

    def publish_load_average(self, load_avg):
        """
        Publishes the given load average value to the thrift server as a ThriftEvent
        :param float load_avg: load average value
        """

        event = ThriftEvent()
        event.payloadData.append(self.cartridge_agent_config.cluster_id)
        event.payloadData.append(self.cartridge_agent_config.cluster_instance_id)
        event.payloadData.append(self.cartridge_agent_config.network_partition_id)
        event.payloadData.append(self.cartridge_agent_config.member_id)
        event.payloadData.append(self.cartridge_agent_config.partition_id)
        event.payloadData.append(constants.LOAD_AVERAGE)
        event.payloadData.append(float(load_avg))

        HealthStatisticsPublisher.log.debug("Publishing cep event: [stream] %r [version] %r" % (self.stream_definition.name, self.stream_definition.version))
        self.publisher.publish(event)
예제 #10
0
class LogPublisherManager(Thread):
    """
    A log publishing thread management thread which maintains a log publisher for each log file. Also defines a stream
    definition and the BAM/CEP server information for a single publishing context.
    """

    @staticmethod
    def define_stream():
        """
        Creates a stream definition for Log Publishing
        :return: A StreamDefinition object with the required attributes added
        :rtype : StreamDefinition
        """
        # stream definition
        stream_definition = StreamDefinition()
        valid_tenant_id = LogPublisherManager.get_valid_tenant_id(CartridgeAgentConfiguration().tenant_id)
        alias = LogPublisherManager.get_alias(CartridgeAgentConfiguration().cluster_id)
        stream_name = "logs." + valid_tenant_id + "." \
                      + alias + "." + LogPublisherManager.get_current_date()
        stream_version = "1.0.0"

        stream_definition.name = stream_name
        stream_definition.version = stream_version
        stream_definition.description = "Apache Stratos Instance Log Publisher"
        stream_definition.add_metadata_attribute("memberId", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("tenantID", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("serverName", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("appName", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("logTime", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("priority", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("message", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("logger", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("ip", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("instance", StreamDefinition.STRING)
        stream_definition.add_payloaddata_attribute("stacktrace", StreamDefinition.STRING)

        return stream_definition

    def __init__(self, logfile_paths):
        Thread.__init__(self)
        self.logfile_paths = logfile_paths
        self.publishers = {}
        self.ports = []
        self.ports.append(DataPublisherConfiguration.get_instance().monitoring_server_port)
        self.ports.append(DataPublisherConfiguration.get_instance().monitoring_server_secure_port)

        self.cartridge_agent_config = CartridgeAgentConfiguration()

        cartridgeagentutils.wait_until_ports_active(
            DataPublisherConfiguration.get_instance().monitoring_server_ip,
            self.ports,
            int(self.cartridge_agent_config.read_property("port.check.timeout", critical=False)))

        ports_active = cartridgeagentutils.check_ports_active(
            DataPublisherConfiguration.get_instance().monitoring_server_ip,
            self.ports)

        if not ports_active:
            raise DataPublisherException("Monitoring server not active, data publishing is aborted")

        self.stream_definition = self.define_stream()

    def run(self):
        if self.logfile_paths is not None and len(self.logfile_paths):
            for log_path in self.logfile_paths:
                # thread for each log file
                publisher = self.get_publisher(log_path)
                publisher.start()

    def get_publisher(self, log_path):
        """
        Retrieve the publisher for the specified log file path. Creates a new LogPublisher if one is not available
        :return: The LogPublisher object
        :rtype : LogPublisher
        """
        if log_path not in self.publishers:
            self.publishers[log_path] = LogPublisher(log_path, self.stream_definition)

        return self.publishers[log_path]

    def terminate_publisher(self, log_path):
        """
        Terminates the LogPublisher thread associated with the specified log file
        """
        if log_path in self.publishers:
            self.publishers[log_path].terminate()

    def terminate_all_publishers(self):
        """
        Terminates all LogPublisher threads
        """
        for publisher in self.publishers:
            publisher.terminate()

    @staticmethod
    def get_valid_tenant_id(tenant_id):
        if tenant_id == constants.INVALID_TENANT_ID \
                or tenant_id == constants.SUPER_TENANT_ID:
            return "0"

        return tenant_id

    @staticmethod
    def get_alias(cluster_id):
        try:
            alias = cluster_id.split("\\.")[0]
        except:
            alias = cluster_id

        return alias

    @staticmethod
    def get_current_date():
        """
        Returns the current date formatted as yyyy-MM-dd
        :return: Formatted date string
        :rtype : str
        """
        return datetime.date.today().strftime(constants.DATE_FORMAT)
예제 #11
0
class DataPublisherConfiguration:
    """
    A singleton implementation to access configuration information for data publishing to BAM/CEP
    TODO: perfect singleton impl ex: Borg
    """

    __instance = None
    log = LogFactory().get_log(__name__)

    @staticmethod
    def get_instance():
        """
        Singleton instance retriever
        :return: Instance
        :rtype : DataPublisherConfiguration
        """
        if DataPublisherConfiguration.__instance is None:
            DataPublisherConfiguration.__instance = DataPublisherConfiguration()

        return DataPublisherConfiguration.__instance

    def __init__(self):
        self.enabled = False
        self.monitoring_server_ip = None
        self.monitoring_server_port = None
        self.monitoring_server_secure_port = None
        self.admin_username = None
        self.admin_password = None
        self.cartridge_agent_config = CartridgeAgentConfiguration()

        self.read_config()

    def read_config(self):
        self.enabled = True if self.cartridge_agent_config.read_property(constants.MONITORING_PUBLISHER_ENABLED, False).strip().lower() == "true" else False
        if not self.enabled:
            DataPublisherConfiguration.log.info("Data Publisher disabled")
            return

        DataPublisherConfiguration.log.info("Data Publisher enabled")

        self.monitoring_server_ip = self.cartridge_agent_config.read_property(constants.MONITORING_RECEIVER_IP, False)
        if self.monitoring_server_ip is None or self.monitoring_server_ip.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_RECEIVER_IP)

        self.monitoring_server_port = self.cartridge_agent_config.read_property(constants.MONITORING_RECEIVER_PORT, False)
        if self.monitoring_server_port is None or self.monitoring_server_port.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_RECEIVER_PORT)

        self.monitoring_server_secure_port = self.cartridge_agent_config.read_property("monitoring.server.secure.port", False)
        if self.monitoring_server_secure_port is None or self.monitoring_server_secure_port.strip() == "":
            raise RuntimeError("System property not found: monitoring.server.secure.port")

        self.admin_username = self.cartridge_agent_config.read_property(constants.MONITORING_SERVER_ADMIN_USERNAME, False)
        if self.admin_username is None or self.admin_username.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_SERVER_ADMIN_USERNAME)

        self.admin_password = self.cartridge_agent_config.read_property(constants.MONITORING_SERVER_ADMIN_PASSWORD, False)
        if self.admin_password is None or self.admin_password.strip() == "":
            raise RuntimeError("System property not found: " + constants.MONITORING_SERVER_ADMIN_PASSWORD)

        DataPublisherConfiguration.log.info("Data Publisher configuration initialized")
예제 #12
0
class CartridgeAgent(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)

        self.__tenant_context_initialized = False
        self.__log_publish_manager = None
        self.__terminated = False
        self.__log = LogFactory().get_log(__name__)
        self.__config = CartridgeAgentConfiguration()

        mb_ip = self.__config.read_property(constants.MB_IP)
        mb_port = self.__config.read_property(constants.MB_PORT)

        self.__inst_topic_subscriber = EventSubscriber(constants.INSTANCE_NOTIFIER_TOPIC, mb_ip, mb_port)
        self.__tenant_topic_subscriber = EventSubscriber(constants.TENANT_TOPIC, mb_ip, mb_port)
        self.__app_topic_subscriber = EventSubscriber(constants.APPLICATION_SIGNUP, mb_ip, mb_port)
        self.__topology_event_subscriber = EventSubscriber(constants.TOPOLOGY_TOPIC, mb_ip, mb_port)

        self.__event_handler = EventHandler()

    def run(self):
        self.__log.info("Starting Cartridge Agent...")

        # Start topology event receiver thread
        self.register_topology_event_listeners()

        # wait until complete topology message is received to get LB IP
        self.wait_for_complete_topology()

        # wait for member initialized event
        while not self.__config.initialized:
            self.__log.debug("Waiting for cartridge agent to be initialized...")
            time.sleep(1)

        # Start instance notifier listener thread
        self.register_instance_topic_listeners()

        # Start tenant event receiver thread
        self.register_tenant_event_listeners()

        # start application signup event listener
        self.register_application_signup_event_listeners()

        # Execute instance started shell script
        self.__event_handler.on_instance_started_event()

        # Publish instance started event
        cartridgeagentpublisher.publish_instance_started_event()

        # Execute start servers extension
        try:
            self.__event_handler.start_server_extension()
        except Exception as e:
            self.__log.exception("Error processing start servers event: %s" % e)

        # check if artifact management is required before publishing instance activated event
        repo_url = self.__config.repo_url
        if repo_url is None or str(repo_url).strip() == "":
            self.__log.info("No artifact repository found")
            self.__event_handler.on_instance_activated_event()
            cartridgeagentpublisher.publish_instance_activated_event()
        else:
            self.__log.info(
                "Artifact repository found, waiting for artifact updated event to checkout artifacts: [repo_url] %s",
                repo_url)

        persistence_mapping_payload = self.__config.persistence_mappings
        if persistence_mapping_payload is not None:
            self.__event_handler.volume_mount_extension(persistence_mapping_payload)

        # start log publishing thread
        if DataPublisherConfiguration.get_instance().enabled:
            log_file_paths = self.__config.log_file_paths
            if log_file_paths is None:
                self.__log.exception("No valid log file paths found, no logs will be published")
            else:
                self.__log_publish_manager = LogPublisherManager(log_file_paths)
                self.__log_publish_manager.start()

        # run until terminated
        while not self.__terminated:
            time.sleep(1)

        if DataPublisherConfiguration.get_instance().enabled:
            self.__log_publish_manager.terminate_all_publishers()

    def terminate(self):
        """
        Allows the CartridgeAgent thread to be terminated

        :return: void
        """
        self.__terminated = True
        
    def register_instance_topic_listeners(self):
        self.__log.debug("Starting instance notifier event message receiver thread")

        self.__inst_topic_subscriber.register_handler("ArtifactUpdatedEvent", self.on_artifact_updated)
        self.__inst_topic_subscriber.register_handler("InstanceCleanupMemberEvent", self.on_instance_cleanup_member)
        self.__inst_topic_subscriber.register_handler("InstanceCleanupClusterEvent", self.on_instance_cleanup_cluster)

        self.__inst_topic_subscriber.start()
        self.__log.info("Instance notifier event message receiver thread started")

        # wait till subscribed to continue
        while not self.__inst_topic_subscriber.is_subscribed():
            time.sleep(1)

    def register_topology_event_listeners(self):
        self.__log.debug("Starting topology event message receiver thread")

        self.__topology_event_subscriber.register_handler("MemberActivatedEvent", self.on_member_activated)
        self.__topology_event_subscriber.register_handler("MemberTerminatedEvent", self.on_member_terminated)
        self.__topology_event_subscriber.register_handler("MemberSuspendedEvent", self.on_member_suspended)
        self.__topology_event_subscriber.register_handler("CompleteTopologyEvent", self.on_complete_topology)
        self.__topology_event_subscriber.register_handler("MemberStartedEvent", self.on_member_started)
        self.__topology_event_subscriber.register_handler("MemberCreatedEvent", self.on_member_created)
        self.__topology_event_subscriber.register_handler("MemberInitializedEvent", self.on_member_initialized)

        self.__topology_event_subscriber.start()
        self.__log.info("Cartridge agent topology receiver thread started")

        # wait till subscribed to continue
        while not self.__topology_event_subscriber.is_subscribed():
            time.sleep(1)

    def register_tenant_event_listeners(self):
        self.__log.debug("Starting tenant event message receiver thread")
        self.__tenant_topic_subscriber.register_handler("DomainMappingAddedEvent",
                                                        self.on_domain_mapping_added)
        self.__tenant_topic_subscriber.register_handler("DomainsMappingRemovedEvent",
                                                        self.on_domain_mapping_removed)
        self.__tenant_topic_subscriber.register_handler("CompleteTenantEvent", self.on_complete_tenant)
        self.__tenant_topic_subscriber.register_handler("TenantSubscribedEvent", self.on_tenant_subscribed)

        self.__tenant_topic_subscriber.start()
        self.__log.info("Tenant event message receiver thread started")

        # wait till subscribed to continue
        while not self.__tenant_topic_subscriber.is_subscribed():
            time.sleep(1)

    def register_application_signup_event_listeners(self):
        self.__log.debug("Starting application signup event message receiver thread")
        self.__app_topic_subscriber.register_handler("ApplicationSignUpRemovedEvent",
                                                     self.on_application_signup_removed)

        self.__app_topic_subscriber.start()
        self.__log.info("Application signup event message receiver thread started")

        # wait till subscribed to continue
        while not self.__app_topic_subscriber.is_subscribed():
            time.sleep(1)

    def on_artifact_updated(self, msg):
        event_obj = ArtifactUpdatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_artifact_updated_event(event_obj)

    def on_instance_cleanup_member(self, msg):
        member_in_payload = self.__config.member_id
        event_obj = InstanceCleanupMemberEvent.create_from_json(msg.payload)
        member_in_event = event_obj.member_id
        if member_in_payload == member_in_event:
            self.__event_handler.on_instance_cleanup_member_event()

    def on_instance_cleanup_cluster(self, msg):
        event_obj = InstanceCleanupClusterEvent.create_from_json(msg.payload)
        cluster_in_payload = self.__config.cluster_id
        cluster_in_event = event_obj.cluster_id
        instance_in_payload = self.__config.cluster_instance_id
        instance_in_event = event_obj.cluster_instance_id

        if cluster_in_event == cluster_in_payload and instance_in_payload == instance_in_event:
            self.__event_handler.on_instance_cleanup_cluster_event()

    def on_member_created(self, msg):
        self.__log.debug("Member created event received: %r" % msg.payload)

    def on_member_initialized(self, msg):
        self.__log.debug("Member initialized event received: %r" % msg.payload)

        if not TopologyContext.topology.initialized:
            return

        self.__event_handler.on_member_initialized_event()

    def on_member_activated(self, msg):
        self.__log.debug("Member activated event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberActivatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_activated_event(event_obj)

    def on_member_terminated(self, msg):
        self.__log.debug("Member terminated event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberTerminatedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_terminated_event(event_obj)

    def on_member_suspended(self, msg):
        self.__log.debug("Member suspended event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberSuspendedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_suspended_event(event_obj)

    def on_complete_topology(self, msg):
        if not TopologyContext.topology.initialized:
            self.__log.debug("Complete topology event received")
            event_obj = CompleteTopologyEvent.create_from_json(msg.payload)
            TopologyContext.update(event_obj.topology)
            self.__event_handler.on_complete_topology_event(event_obj)
        else:
            self.__log.debug("Complete topology event updating task disabled")

    def on_member_started(self, msg):
        self.__log.debug("Member started event received: %r" % msg.payload)
        if not TopologyContext.topology.initialized:
            return

        event_obj = MemberStartedEvent.create_from_json(msg.payload)
        self.__event_handler.on_member_started_event(event_obj)

    def on_domain_mapping_added(self, msg):
        self.__log.debug("Subscription domain added event received : %r" % msg.payload)
        event_obj = DomainMappingAddedEvent.create_from_json(msg.payload)
        self.__event_handler.on_domain_mapping_added_event(event_obj)

    def on_domain_mapping_removed(self, msg):
        self.__log.debug("Subscription domain removed event received : %r" % msg.payload)
        event_obj = DomainMappingRemovedEvent.create_from_json(msg.payload)
        self.__event_handler.on_domain_mapping_removed_event(event_obj)

    def on_complete_tenant(self, msg):
        if not self.__tenant_context_initialized:
            self.__log.debug("Complete tenant event received")
            event_obj = CompleteTenantEvent.create_from_json(msg.payload)
            TenantContext.update(event_obj.tenants)

            self.__event_handler.on_complete_tenant_event(event_obj)
            self.__tenant_context_initialized = True
        else:
            self.__log.debug("Complete tenant event updating task disabled")

    def on_tenant_subscribed(self, msg):
        self.__log.debug("Tenant subscribed event received: %r" % msg.payload)
        event_obj = TenantSubscribedEvent.create_from_json(msg.payload)
        self.__event_handler.on_tenant_subscribed_event(event_obj)

    def on_application_signup_removed(self, msg):
        self.__log.debug("Application signup removed event received: %r" % msg.payload)
        event_obj = ApplicationSignUpRemovedEvent.create_from_json(msg.payload)
        self.__event_handler.on_application_signup_removed_event(event_obj)

    def wait_for_complete_topology(self):
        while not TopologyContext.topology.initialized:
            self.__log.info("Waiting for complete topology event...")
            time.sleep(5)
        self.__log.info("Complete topology event received")
예제 #13
0
class EventHandler:
    """
    Event execution related logic
    """

    def __init__(self):
        self.__log = LogFactory().get_log(__name__)
        self.__config = CartridgeAgentConfiguration()
        self.__plugin_manager = None
        self.__plugins = {}
        """ :type dict{str: [PluginInfo]} : """
        self.__artifact_mgt_plugins = []
        self.__plugin_manager, self.__plugins, self.__artifact_mgt_plugins = self.initialize_plugins()

    def initialize_plugins(self):
        self.__log.info("Collecting and loading plugins")

        try:
            plugin_manager = PluginManager()
            # TODO: change plugin descriptor extensions, plugin_manager.setPluginInfoExtension(AGENT_PLUGIN_EXT)
            plugin_manager.setCategoriesFilter({
                CARTRIDGE_AGENT_PLUGIN: ICartridgeAgentPlugin,
                ARTIFACT_MGT_PLUGIN: IArtifactManagementPlugin
            })

            plugin_manager.setPluginPlaces([self.__config.read_property(constants.PLUGINS_DIR)])

            plugin_manager.collectPlugins()

            # activate cartridge agent plugins
            plugins = plugin_manager.getPluginsOfCategory(CARTRIDGE_AGENT_PLUGIN)
            grouped_plugins = {}
            for plugin_info in plugins:
                self.__log.debug("Found plugin [%s] at [%s]" % (plugin_info.name, plugin_info.path))
                plugin_manager.activatePluginByName(plugin_info.name)
                self.__log.info("Activated plugin [%s]" % plugin_info.name)

                mapped_events = plugin_info.description.split(",")
                for mapped_event in mapped_events:
                    if mapped_event.strip() != "":
                        if grouped_plugins.get(mapped_event) is None:
                            grouped_plugins[mapped_event] = []

                        grouped_plugins[mapped_event].append(plugin_info)

            # activate artifact management plugins
            artifact_mgt_plugins = plugin_manager.getPluginsOfCategory(ARTIFACT_MGT_PLUGIN)
            for plugin_info in artifact_mgt_plugins:
                self.__log.debug("Found artifact management plugin [%s] at [%s]" % (plugin_info.name, plugin_info.path))
                plugin_manager.activatePluginByName(plugin_info.name)
                self.__log.info("Activated artifact management plugin [%s]" % plugin_info.name)

            return plugin_manager, grouped_plugins, artifact_mgt_plugins
        except ParameterNotFoundException as e:
            self.__log.exception("Could not load plugins. Plugins directory not set: %s" % e)
            return None, None, None
        except Exception as e:
            self.__log.exception("Error while loading plugin: %s" % e)
            return None, None, None

    def execute_plugins_for_event(self, event, plugin_values):
        """ For each plugin registered for the specified event, start a plugin execution thread
        :param str event: The event name string
        :param dict plugin_values: the values to be passed to the plugin
        :return:
        """
        try:
            plugin_values = self.get_values_for_plugins(plugin_values)
            plugin_values["EVENT"] = event
            plugins_for_event = self.__plugins.get(event)
            if plugins_for_event is not None:
                for plugin_info in plugins_for_event:
                    self.__log.debug("Executing plugin %s for event %s" % (plugin_info.name, event))
                    plugin_thread = PluginExecutor(plugin_info, plugin_values)
                    plugin_thread.start()

                    # block till plugin run completes.
                    plugin_thread.join()
            else:
                self.__log.debug("No plugins registered for event %s" % event)
        except Exception as e:
            self.__log.exception("Error while executing plugin for event %s: %s" % (event, e))

    def on_instance_started_event(self):
        self.__log.debug("Processing instance started event...")
        self.execute_plugins_for_event("InstanceStartedEvent", {})

    def on_instance_activated_event(self):
        self.__log.debug("Processing instance activated event...")
        self.execute_plugins_for_event("InstanceActivatedEvent", {})

    def get_repo_path_for_tenant(self, tenant_id, git_local_repo_path, is_multitenant):
        repo_path = ""

        if is_multitenant:
            if tenant_id == SUPER_TENANT_ID:
                # super tenant, /repository/deploy/server/
                super_tenant_repo_path = self.__config.super_tenant_repository_path
                # "app_path"
                repo_path += git_local_repo_path

                if super_tenant_repo_path is not None and super_tenant_repo_path != "":
                    super_tenant_repo_path = super_tenant_repo_path if super_tenant_repo_path.startswith("/") \
                        else "/" + super_tenant_repo_path
                    super_tenant_repo_path = super_tenant_repo_path if super_tenant_repo_path.endswith("/") \
                        else super_tenant_repo_path + "/"
                    # "app_path/repository/deploy/server/"
                    repo_path += super_tenant_repo_path
                else:
                    # "app_path/repository/deploy/server/"
                    repo_path += SUPER_TENANT_REPO_PATH

            else:
                # normal tenant, /repository/tenants/tenant_id
                tenant_repo_path = self.__config.tenant_repository_path
                # "app_path"
                repo_path += git_local_repo_path

                if tenant_repo_path is not None and tenant_repo_path != "":
                    tenant_repo_path = tenant_repo_path if tenant_repo_path.startswith("/") else "/" + tenant_repo_path
                    tenant_repo_path = tenant_repo_path if tenant_repo_path.endswith("/") else tenant_repo_path + "/"
                    # "app_path/repository/tenants/244653444"
                    repo_path += tenant_repo_path + tenant_id
                else:
                    # "app_path/repository/tenants/244653444"
                    repo_path += TENANT_REPO_PATH + tenant_id

                # tenant_dir_path = git_local_repo_path + AgentGitHandler.TENANT_REPO_PATH + tenant_id
                # GitUtils.create_dir(repo_path)
        else:
            # not multi tenant, app_path
            repo_path = git_local_repo_path

        self.__log.debug("Repo path returned : %r" % repo_path)
        return repo_path

    def on_artifact_updated_event(self, artifacts_updated_event):
        self.__log.info("Processing Artifact update event: [tenant] %s [cluster] %s [status] %s" %
                        (artifacts_updated_event.tenant_id,
                         artifacts_updated_event.cluster_id,
                         artifacts_updated_event.status))

        cluster_id_event = str(artifacts_updated_event.cluster_id).strip()
        cluster_id_payload = self.__config.cluster_id
        repo_url = str(artifacts_updated_event.repo_url).strip()

        if (repo_url != "") and (cluster_id_payload is not None) and (cluster_id_payload == cluster_id_event):
            local_repo_path = self.__config.app_path

            repo_password = None
            if artifacts_updated_event.repo_password is not None:
                secret = self.__config.cartridge_key
                repo_password = cartridgeagentutils.decrypt_password(artifacts_updated_event.repo_password, secret)

            repo_username = artifacts_updated_event.repo_username
            tenant_id = artifacts_updated_event.tenant_id
            is_multitenant = self.__config.is_multitenant
            commit_enabled = artifacts_updated_event.commit_enabled

            self.__log.info("Executing git checkout")

            # create repo object
            local_repo_path = self.get_repo_path_for_tenant(tenant_id, local_repo_path, is_multitenant)
            repo_info = Repository(repo_url, repo_username, repo_password, local_repo_path, tenant_id, commit_enabled)

            # checkout code
            subscribe_run, updated = AgentGitHandler.checkout(repo_info)
            # execute artifact updated extension
            plugin_values = {"ARTIFACT_UPDATED_CLUSTER_ID": artifacts_updated_event.cluster_id,
                             "ARTIFACT_UPDATED_TENANT_ID": artifacts_updated_event.tenant_id,
                             "ARTIFACT_UPDATED_REPO_URL": artifacts_updated_event.repo_url,
                             "ARTIFACT_UPDATED_REPO_PASSWORD": artifacts_updated_event.repo_password,
                             "ARTIFACT_UPDATED_REPO_USERNAME": artifacts_updated_event.repo_username,
                             "ARTIFACT_UPDATED_STATUS": artifacts_updated_event.status}

            self.execute_plugins_for_event("ArtifactUpdatedEvent", plugin_values)

            if subscribe_run:
                # publish instanceActivated
                cartridgeagentpublisher.publish_instance_activated_event()
            elif updated:
                # updated on pull
                self.on_artifact_update_scheduler_event(tenant_id)

            update_artifacts = self.__config.read_property(constants.ENABLE_ARTIFACT_UPDATE, False)
            update_artifacts = True if str(update_artifacts).strip().lower() == "true" else False
            if update_artifacts:
                auto_commit = self.__config.is_commits_enabled
                auto_checkout = self.__config.is_checkout_enabled

                try:
                    update_interval = int(self.__config.artifact_update_interval)
                except ValueError:
                    self.__log.exception("Invalid artifact sync interval specified.")
                    update_interval = 10

                self.__log.info("Artifact updating task enabled, update interval: %s seconds" % update_interval)

                self.__log.info("Auto Commit is turned %s " % ("on" if auto_commit else "off"))
                self.__log.info("Auto Checkout is turned %s " % ("on" if auto_checkout else "off"))

                AgentGitHandler.schedule_artifact_update_task(
                    repo_info,
                    auto_checkout,
                    auto_commit,
                    update_interval)

    def on_artifact_update_scheduler_event(self, tenant_id):
        self.__log.info("Processing Artifact update scheduler event...")
        plugin_values = {"ARTIFACT_UPDATED_TENANT_ID": str(tenant_id),
                         "ARTIFACT_UPDATED_SCHEDULER": str(True)}

        self.execute_plugins_for_event("ArtifactUpdateSchedulerEvent", plugin_values)

    def on_instance_cleanup_cluster_event(self):
        self.__log.info("Processing instance cleanup cluster event...")
        self.cleanup("InstanceCleanupClusterEvent")

    def on_instance_cleanup_member_event(self):
        self.__log.info("Processing instance cleanup member event...")
        self.cleanup("InstanceCleanupMemberEvent")

    def on_member_activated_event(self, member_activated_event):
        self.__log.info("Processing Member activated event: [service] %r [cluster] %r [member] %r"
                        % (member_activated_event.service_name,
                           member_activated_event.cluster_id,
                           member_activated_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_activated_event.service_name,
            member_activated_event.cluster_id,
            member_activated_event.member_id)

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member activated event")
            return

        self.execute_plugins_for_event("MemberActivatedEvent", {})

    def on_complete_topology_event(self, complete_topology_event):
        self.__log.debug("Processing Complete topology event...")

        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_initialized = self.check_member_state_in_topology(
            service_name_in_payload,
            cluster_id_in_payload,
            member_id_in_payload)

        self.__log.debug("Member initialized %s", member_initialized)
        if member_initialized:
            # Set cartridge agent as initialized since member is available and it is in initialized state
            self.__config.initialized = True

        topology = complete_topology_event.get_topology()
        service = topology.get_service(service_name_in_payload)
        cluster = service.get_cluster(cluster_id_in_payload)

        plugin_values = {"TOPOLOGY_JSON": json.dumps(topology.json_str),
                         "MEMBER_LIST_JSON": json.dumps(cluster.member_list_json)}

        self.execute_plugins_for_event("CompleteTopologyEvent", plugin_values)

    def on_member_initialized_event(self):
        """
         Member initialized event is sent by cloud controller once volume attachment and
         ip address allocation is completed successfully
        :return:
        """
        self.__log.debug("Processing Member initialized event...")

        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_exists = self.member_exists_in_topology(service_name_in_payload, cluster_id_in_payload,
                                                       member_id_in_payload)

        self.__log.debug("Member exists: %s" % member_exists)

        if member_exists:
            self.__config.initialized = True

        self.execute_plugins_for_event("MemberInitializedEvent", {})

    def on_complete_tenant_event(self, complete_tenant_event):
        self.__log.debug("Processing Complete tenant event...")

        tenant_list_json = complete_tenant_event.tenant_list_json
        self.__log.debug("Complete tenants:" + json.dumps(tenant_list_json))

        plugin_values = {"TENANT_LIST_JSON": json.dumps(tenant_list_json)}

        self.execute_plugins_for_event("CompleteTenantEvent", plugin_values)

    def on_member_terminated_event(self, member_terminated_event):
        self.__log.info("Processing Member terminated event: [service] %s [cluster] %s [member] %s" %
                        (member_terminated_event.service_name, member_terminated_event.cluster_id,
                         member_terminated_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_terminated_event.service_name,
            member_terminated_event.cluster_id,
            member_terminated_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member terminated event")
            return

        self.execute_plugins_for_event("MemberTerminatedEvent", {})

    def on_member_suspended_event(self, member_suspended_event):
        self.__log.info("Processing Member suspended event: [service] %s [cluster] %s [member] %s" %
                        (member_suspended_event.service_name, member_suspended_event.cluster_id,
                         member_suspended_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_suspended_event.service_name,
            member_suspended_event.cluster_id,
            member_suspended_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member suspended event")
            return

        self.execute_plugins_for_event("MembeSuspendedEvent", {})

    def on_member_started_event(self, member_started_event):
        self.__log.info("Processing Member started event: [service] %s [cluster] %s [member] %s" %
                        (member_started_event.service_name, member_started_event.cluster_id,
                         member_started_event.member_id))

        member_initialized = self.check_member_state_in_topology(
            member_started_event.service_name,
            member_started_event.cluster_id,
            member_started_event.member_id
        )

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute member started event")
            return

        self.execute_plugins_for_event("MemberStartedEvent", {})

    def start_server_extension(self):
        self.__log.info("Processing start server extension...")
        service_name_in_payload = self.__config.service_name
        cluster_id_in_payload = self.__config.cluster_id
        member_id_in_payload = self.__config.member_id

        member_initialized = self.check_member_state_in_topology(service_name_in_payload, cluster_id_in_payload,
                                                                 member_id_in_payload)

        if not member_initialized:
            self.__log.error("Member has not initialized, failed to execute start server event")
            return

        self.execute_plugins_for_event("StartServers", {})

    def volume_mount_extension(self, persistence_mappings_payload):
        self.__log.info("Processing volume mount extension...")
        self.execute_plugins_for_event("VolumeMount", persistence_mappings_payload)

    def on_subscription_domain_added_event(self, subscription_domain_added_event):
        tenant_domain = EventHandler.find_tenant_domain(subscription_domain_added_event.tenant_id)
        self.__log.info(
            "Processing Subscription domain added event: [tenant-id] " + subscription_domain_added_event.tenant_id +
            " [tenant-domain] " + tenant_domain + " [domain-name] " + subscription_domain_added_event.domain_name +
            " [application-context] " + subscription_domain_added_event.application_context
        )

        plugin_values = {"SUBSCRIPTION_SERVICE_NAME": subscription_domain_added_event.service_name,
                         "SUBSCRIPTION_DOMAIN_NAME": subscription_domain_added_event.domain_name,
                         "SUBSCRIPTION_TENANT_ID": int(subscription_domain_added_event.tenant_id),
                         "SUBSCRIPTION_TENANT_DOMAIN": tenant_domain,
                         "SUBSCRIPTION_APPLICATION_CONTEXT":
                             subscription_domain_added_event.application_context}

        self.execute_plugins_for_event("SubscriptionDomainAddedEvent", plugin_values)

    def on_subscription_domain_removed_event(self, subscription_domain_removed_event):
        tenant_domain = EventHandler.find_tenant_domain(subscription_domain_removed_event.tenant_id)
        self.__log.info(
            "Subscription domain removed event received: [tenant-id] " + subscription_domain_removed_event.tenant_id +
            " [tenant-domain] " + tenant_domain + " [domain-name] " + subscription_domain_removed_event.domain_name
        )

        plugin_values = {"SUBSCRIPTION_SERVICE_NAME": subscription_domain_removed_event.service_name,
                         "SUBSCRIPTION_DOMAIN_NAME": subscription_domain_removed_event.domain_name,
                         "SUBSCRIPTION_TENANT_ID": int(subscription_domain_removed_event.tenant_id),
                         "SUBSCRIPTION_TENANT_DOMAIN": tenant_domain}

        self.execute_plugins_for_event("SubscriptionDomainRemovedEvent", plugin_values)

    def on_copy_artifacts_extension(self, src, dest):
        self.__log.info("Processing Copy artifacts extension...")
        plugin_values = {"SOURCE": src, "DEST": dest}
        self.execute_plugins_for_event("CopyArtifacts", plugin_values)

    def on_tenant_subscribed_event(self, tenant_subscribed_event):
        self.__log.info(
            "Processing Tenant subscribed event: [tenant] " + tenant_subscribed_event.tenant_id +
            " [service] " + tenant_subscribed_event.service_name + " [cluster] " + tenant_subscribed_event.cluster_ids
        )

        self.execute_plugins_for_event("TenantSubscribedEvent", {})

    def on_application_signup_removed_event(self, application_signup_removal_event):
        self.__log.info(
            "Processing Tenant unsubscribed event: [tenant] " + application_signup_removal_event.tenantId +
            " [application ID] " + application_signup_removal_event.applicationId
        )

        if self.__config.application_id == application_signup_removal_event.applicationId:
            AgentGitHandler.remove_repo(application_signup_removal_event.tenant_id)

        self.execute_plugins_for_event("ApplicationSignUpRemovedEvent", {})

    def cleanup(self, event):
        self.__log.info("Executing cleaning up the data in the cartridge instance...")

        cartridgeagentpublisher.publish_maintenance_mode_event()

        self.execute_plugins_for_event(event, {})
        self.__log.info("cleaning up finished in the cartridge instance...")

        self.__log.info("publishing ready to shutdown event...")
        cartridgeagentpublisher.publish_instance_ready_to_shutdown_event()

    def check_member_state_in_topology(self, service_name, cluster_id, member_id):
        topology = TopologyContext.get_topology()
        service = topology.get_service(service_name)
        if service is None:
            self.__log.error("Service not found in topology [service] %s" % service_name)
            return False

        cluster = service.get_cluster(cluster_id)
        if cluster is None:
            self.__log.error("Cluster id not found in topology [cluster] %s" % cluster_id)
            return False

        activated_member = cluster.get_member(member_id)
        if activated_member is None:
            self.__log.error("Member id not found in topology [member] %s" % member_id)
            return False

        if activated_member.status != MemberStatus.Initialized:
            return False

        return True

    def member_exists_in_topology(self, service_name, cluster_id, member_id):
        topology = TopologyContext.get_topology()
        service = topology.get_service(service_name)
        if service is None:
            self.__log.error("Service not found in topology [service] %s" % service_name)
            return False

        cluster = service.get_cluster(cluster_id)
        if cluster is None:
            self.__log.error("Cluster id not found in topology [cluster] %s" % cluster_id)
            return False

        activated_member = cluster.get_member(member_id)
        if activated_member is None:
            self.__log.error("Member id not found in topology [member] %s" % member_id)
            return False

        return True

    def get_values_for_plugins(self, plugin_values):
        """
        Adds the common parameters to be used by the extension scripts
        :param dict[str, str] plugin_values: Dictionary to be added
        :return: Dictionary with updated parameters
        :rtype: dict[str, str]
        """
        if plugin_values is None:
            plugin_values = {}
        elif type(plugin_values) != dict:
            plugin_values = {"VALUE1": str(plugin_values)}

        plugin_values["APPLICATION_PATH"] = self.__config.app_path
        plugin_values["PARAM_FILE_PATH"] = self.__config.read_property(constants.PARAM_FILE_PATH, False)
        plugin_values["PERSISTENCE_MAPPINGS"] = self.__config.persistence_mappings

        lb_cluster_id_in_payload = self.__config.lb_cluster_id
        lb_private_ip, lb_public_ip = EventHandler.get_lb_member_ip(lb_cluster_id_in_payload)
        plugin_values["LB_IP"] = lb_private_ip if lb_private_ip is not None else self.__config.lb_private_ip
        plugin_values["LB_PUBLIC_IP"] = lb_public_ip if lb_public_ip is not None else self.__config.lb_public_ip

        topology = TopologyContext.get_topology()
        if topology.initialized:
            service = topology.get_service(self.__config.service_name)
            cluster = service.get_cluster(self.__config.cluster_id)
            member_id_in_payload = self.__config.member_id
            member = cluster.get_member(member_id_in_payload)
            EventHandler.add_properties(service.properties, plugin_values, "SERVICE_PROPERTY")
            EventHandler.add_properties(cluster.properties, plugin_values, "CLUSTER_PROPERTY")
            EventHandler.add_properties(member.properties, plugin_values, "MEMBER_PROPERTY")

        plugin_values.update(self.__config.get_payload_params())

        return EventHandler.clean_process_parameters(plugin_values)

    @staticmethod
    def add_properties(properties, params, prefix):
        """
        Adds the given property list to the parameters list with given prefix in the parameter name
        :param dict[str, str] properties: service properties
        :param dict[str, str] params:
        :param str prefix:
        :return: dict[str, str]
        """
        if properties is None or properties.items() is None:
            return

        for key in properties:
            params[prefix + "_" + key] = str(properties[key])

    @staticmethod
    def get_lb_member_ip(lb_cluster_id):
        topology = TopologyContext.get_topology()
        services = topology.get_services()

        for service in services:
            clusters = service.get_clusters()
            for cluster in clusters:
                members = cluster.get_members()
                for member in members:
                    if member.cluster_id == lb_cluster_id:
                        return member.member_default_private_ip, member.member_default_public_ip

        return None, None

    @staticmethod
    def clean_process_parameters(params):
        """
        Removes any null valued parameters before passing them to the extension scripts
        :param dict params:
        :return: cleaned parameters
        :rtype: dict
        """
        for key, value in params.items():
            if value is None:
                del params[key]

        return params

    @staticmethod
    def find_tenant_domain(tenant_id):
        tenant = TenantContext.get_tenant(tenant_id)
        if tenant is None:
            raise RuntimeError("Tenant could not be found: [tenant-id] %s" % tenant_id)

        return tenant.tenant_domain