You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by im...@apache.org on 2015/02/10 16:50:21 UTC

[03/17] stratos git commit: Moving python cartridge agent automation tests to python cartridge agent component

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/__init__.py
new file mode 100644
index 0000000..2456923
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/__init__.py
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/events.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/events.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/events.py
new file mode 100644
index 0000000..8456854
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/notifier/events.py
@@ -0,0 +1,82 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+
+class ArtifactUpdatedEvent:
+    def __init__(self):
+        self.cluster_id = None
+        """ :type : str  """
+        self.status = None
+        """ :type : str  """
+        self.repo_username = None
+        """ :type : str  """
+        self.repo_password = None
+        """ :type : str  """
+        self.repo_url = None
+        """ :type : str  """
+        self.tenant_id = None
+        """ :type : int  """
+        self.commit_enabled = None
+        """ :type : bool  """
+        self.instance_id=None
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = ArtifactUpdatedEvent()
+
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.status = json_obj["status"] if "status" in json_obj else None
+        instance.repo_username = json_obj["repoUserName"] if "repoUserName" in json_obj else None
+        instance.repo_password = json_obj["repoPassword"] if "repoPassword" in json_obj else None
+        instance.tenant_id = json_obj["tenantId"] if "tenantId" in json_obj else None
+        instance.repo_url = json_obj["repoURL"] if "repoURL" in json_obj else ""
+        instance.commit_enabled = json_obj["commitEnabled"] if "commitEnabled" in json_obj else None
+
+        return instance
+
+
+class InstanceCleanupClusterEvent:
+    def __init__(self, cluster_id, cluster_instance_id):
+        self.cluster_id = cluster_id
+        """ :type : str  """
+        self.cluster_instance_id = cluster_instance_id
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance_cluster_id = json_obj["instanceClusterId"] if "clusterId" in json_obj else None
+
+        return InstanceCleanupClusterEvent(cluster_id, instance_cluster_id)
+
+
+class InstanceCleanupMemberEvent:
+    def __init__(self, member_id):
+        self.member_id = member_id
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        m_id = json_obj["memberId"] if "memberId" in json_obj else None
+
+        return InstanceCleanupMemberEvent(m_id)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/__init__.py
new file mode 100644
index 0000000..2456923
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/__init__.py
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/events.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/events.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/events.py
new file mode 100644
index 0000000..db35987
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/instance/status/events.py
@@ -0,0 +1,118 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+
+class InstanceActivatedEvent:
+    def __init__(self, service_name, cluster_id, cluster_instance_id, member_id, instance_id,
+                 network_partition_id, partition_id):
+        self.serviceName = service_name
+        """ :type : str  """
+        self.clusterId = cluster_id
+        """ :type : str  """
+        self.clusterInstanceId = cluster_instance_id
+        """ :type : str  """
+        self.memberId = member_id
+        """ :type : str  """
+        self.instanceId = instance_id
+        """ :type : str  """
+        self.networkPartitionId = network_partition_id
+        """ :type : str  """
+        self.partitionId = partition_id
+        """ :type : str  """
+
+    def to_json(self):
+        return to_json(self)
+
+
+class InstanceStartedEvent:
+    def __init__(self, application_id, service_name, cluster_id, cluster_instance_id, member_id, instance_id,
+                 network_partition_id, partition_id):
+        self.applicationId = application_id
+        """ :type : str  """
+        self.serviceName = service_name
+        """ :type : str  """
+        self.clusterId = cluster_id
+        """ :type : str  """
+        self.clusterInstanceId = cluster_instance_id
+        """ :type : str  """
+        self.memberId = member_id
+        """ :type : str  """
+        self.instanceId = instance_id
+        """ :type : str  """
+        self.networkPartitionId = network_partition_id
+        """ :type : str  """
+        self.partitionId = partition_id
+        """ :type : str  """
+
+    def to_json(self):
+        return to_json(self)
+
+
+class InstanceMaintenanceModeEvent:
+    def __init__(self, service_name, cluster_id, cluster_instance_id, member_id, instance_id,
+                 network_partition_id, partition_id):
+        self.serviceName = service_name
+        """ :type : str  """
+        self.clusterId = cluster_id
+        """ :type : str  """
+        self.clusterInstanceId = cluster_instance_id
+        """ :type : str  """
+        self.memberId = member_id
+        """ :type : str  """
+        self.instanceId = instance_id
+        """ :type : str  """
+        self.networkPartitionId = network_partition_id
+        """ :type : str  """
+        self.partitionId = partition_id
+        """ :type : str  """
+
+    def to_json(self):
+        return to_json(self)
+
+
+class InstanceReadyToShutdownEvent:
+    def __init__(self, service_name, cluster_id, cluster_instance_id, member_id, instance_id,
+                 network_partition_id, partition_id):
+        self.serviceName = service_name
+        """ :type : str  """
+        self.clusterId = cluster_id
+        """ :type : str  """
+        self.clusterInstanceId = cluster_instance_id
+        """ :type : str  """
+        self.memberId = member_id
+        """ :type : str  """
+        self.instanceId = instance_id
+        """ :type : str  """
+        self.networkPartitionId = network_partition_id
+        """ :type : str  """
+        self.partitionId = partition_id
+        """ :type : str  """
+
+    def to_json(self):
+        return to_json(self)
+
+
+def to_json(instance):
+    """
+    common function to serialize status event object
+    :param obj instance:
+    :return: serialized json string
+    :rtype str
+    """
+    return json.dumps(instance, default=lambda o: o.__dict__, sort_keys=True, indent=4)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/events.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/events.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/events.py
new file mode 100644
index 0000000..def2b64
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/tenant/events.py
@@ -0,0 +1,147 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+from ... tenant.tenantcontext import *
+
+
+class SubscriptionDomainAddedEvent():
+
+    def __init__(self):
+        self.tenant_id = None
+        """ :type : int  """
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_ids = None
+        """ :type : list[str]  """
+        self.domain_name = None
+        """ :type : str  """
+        self.application_context = None
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = SubscriptionDomainAddedEvent()
+
+        instance.cluster_ids = json_obj["clusterIds"] if "clusterIds" in json_obj else None
+        instance.tenant_id = json_obj["tenantId"] if "tenantId" in json_obj else None
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.domain_name = json_obj["domainName"] if "domainName" in json_obj else None
+        instance.application_context = json_obj["applicationContext"] if "applicationContext" in json_obj else None
+
+        return instance
+
+
+class SubscriptionDomainRemovedEvent:
+
+    def __init__(self, tenant_id, service_name, cluster_ids, domain_name):
+        self.tenant_id = tenant_id
+        """ :type : int  """
+        self.service_name = service_name
+        """ :type : str  """
+        self.cluster_ids = cluster_ids
+        """ :type : list[str]  """
+        self.domain_name = domain_name
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = SubscriptionDomainRemovedEvent()
+
+        instance.cluster_ids = json_obj["clusterIds"] if "clusterIds" in json_obj else None
+        instance.tenant_id = json_obj["tenantId"] if "tenantId" in json_obj else None
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.domain_name = json_obj["domainName"] if "domainName" in json_obj else None
+
+        return instance
+
+
+class CompleteTenantEvent:
+
+    def __init__(self):
+        self.tenants = []
+        """ :type : list[Tenant]  """
+        self.tenant_list_json = None
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = CompleteTenantEvent()
+        instance.tenants = []
+
+        tenants_str = json_obj["tenants"] if "tenants" in json_obj else None
+        instance.tenant_list_json = tenants_str
+        if tenants_str is not None:
+            for tenant_str in tenants_str:
+                tenant_obj = Tenant(int(tenant_str["tenantId"]), tenant_str["tenantDomain"])
+                for service_name in tenant_str["serviceNameSubscriptionMap"]:
+                    sub_str = tenant_str["serviceNameSubscriptionMap"][service_name]
+                    sub = Subscription(sub_str["serviceName"], sub_str["clusterIds"])
+                    for domain_name in sub_str["subscriptionDomainMap"]:
+                        subdomain_str = sub_str["subscriptionDomainMap"][domain_name]
+                        sub.add_subscription_domain(domain_name, subdomain_str["applicationContext"])
+                    tenant_obj.add_subscription(sub)
+                instance.tenants.append(tenant_obj)
+
+        return instance
+
+
+class TenantSubscribedEvent:
+
+    def __init__(self):
+        self.tenant_id = None
+        """ :type : int  """
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_ids = None
+        """ :type : list[str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = TenantSubscribedEvent()
+
+        instance.tenant_id = json_obj["tenantId"] if "tenantId" in json_obj else None
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_ids = json_obj["clusterIds"] if "clusterIds" in json_obj else None
+
+        return instance
+
+
+class TenantUnsubscribedEvent:
+
+    def __init__(self):
+        self.tenant_id = None
+        """ :type : int  """
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_ids = None
+        """ :type : list[str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = TenantUnsubscribedEvent()
+
+        instance.tenant_id = json_obj["tenantId"] if "tenantId" in json_obj else None
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_ids = json_obj["clusterIds"] if "clusterIds" in json_obj else None
+
+        return instance
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/__init__.py
new file mode 100644
index 0000000..2456923
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/__init__.py
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/events.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/events.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/events.py
new file mode 100644
index 0000000..d606b13
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/event/topology/events.py
@@ -0,0 +1,374 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+from ... topology.topologycontext import *
+
+
+class MemberActivatedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.instance_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+        self.port_map = {}
+        """ :type : dict[str, Port]  """
+        self.member_private_ips = None
+        """ :type : str  """
+
+    def get_port(self, proxy_port):
+        """
+        Returns the port object of the provided port id
+        :param str proxy_port:
+        :return: Port object, None if the port id is invalid
+        :rtype: topology.topologycontext.Port
+        """
+        if proxy_port in self.port_map:
+            return self.port_map[proxy_port]
+
+        return None
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberActivatedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.instance_id = json_obj["instanceId"] if "instanceId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+        #instance.port_map = json_obj["portMap"] if "portMap" in json_obj else {}
+        instance.member_private_ips = json_obj["memberPrivateIPs"] if "memberPrivateIPs" in json_obj else None
+        instance.member_public_ips = json_obj["memberPublicIPs"] if "memberPublicIPs" in json_obj else None
+        instance.member_default_public_ip = json_obj["defaultPublicIP"] if "defaultPublicIP" in json_obj else None
+        instance.member_default_private_ip = json_obj["defaultPrivateIP"] if "defaultPrivateIP" in json_obj else None
+
+        for port_proxy in json_obj["portMap"]:
+            port_str = json_obj["portMap"][port_proxy]
+            port_obj = Port(port_str["protocol"], port_str["value"], port_proxy)
+            instance.port_map[port_proxy] = port_obj
+
+        return instance
+
+
+class MemberTerminatedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.instance_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+        self.properties = {}
+        """ :type : dict[str, str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberTerminatedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.instance_id = json_obj["instanceId"] if "instanceId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+        instance.properties = json_obj["properties"] if "properties" in json_obj else None
+
+        return instance
+
+
+class MemberSuspendedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.instance_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberSuspendedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.instance_id = json_obj["instanceId"] if "instanceId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+
+        return instance
+
+
+class CompleteTopologyEvent:
+
+    def __init__(self):
+        self.topology = None
+        """ :type :  Topology """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = CompleteTopologyEvent()
+
+        topology_str = json_obj["topology"] if "topology" in json_obj else None
+        if topology_str is not None:
+            topology_obj = Topology()
+            topology_obj.initialized = True if str(topology_str["initialized"]).lower == "true" else False
+            topology_obj.json_str = topology_str
+
+            #add service map
+            for service_name in topology_str["serviceMap"]:
+                service_str = topology_str["serviceMap"][service_name]
+
+                service_obj = Service(service_name, service_str["serviceType"])
+                service_obj.properties = service_str["properties"] if "properties" in service_str else None
+                # add ports to port map
+                for port_proxy in service_str["portMap"]:
+                    port_str = service_str["portMap"][port_proxy]
+                    port_obj = Port(port_str["protocol"], port_str["value"], port_proxy)
+                    service_obj.add_port(port_obj)
+
+                #add cluster map
+                for cluster_id in service_str["clusterIdClusterMap"]:
+                    cluster_str = service_str["clusterIdClusterMap"][cluster_id]
+                    cl_service_name = cluster_str["serviceName"]
+                    cl_autoscale_policy_name = cluster_str["autoscalePolicyName"]
+                    cl_deployment_policy_name = cluster_str["deploymentPolicyName"] \
+                        if "deploymentPolicyName" in cluster_str else None
+
+                    cluster_obj = Cluster(cl_service_name, cluster_id,
+                                          cl_deployment_policy_name, cl_autoscale_policy_name)
+                    cluster_obj.hostnames = cluster_str["hostNames"]
+                    cluster_obj.tenant_range = cluster_str["tenantRange"] if "tenantRange" in cluster_str else None
+                    cluster_obj.is_lb_cluster = True if str(cluster_str["isLbCluster"]).lower == "true" else False
+                    cluster_obj.is_kubernetes_cluster = True if str(cluster_str["isKubernetesCluster"]).lower == "true" \
+                        else False
+                    # cluster_obj.status = cluster_str["status"] if "status" in cluster_str else None
+                    cluster_obj.load_balancer_algorithm_name = cluster_str["loadBalanceAlgorithmName"] \
+                        if "loadBalanceAlgorithmName" in cluster_str else None
+                    cluster_obj.properties = cluster_str["properties"] if "properties" in cluster_str else None
+                    cluster_obj.member_list_json = cluster_str["memberMap"]
+                    cluster_obj.app_id = cluster_str["appId"]
+
+                    # add member map
+                    for member_id in cluster_str["memberMap"]:
+                        member_str = cluster_str["memberMap"][member_id]
+                        mm_service_name = member_str["serviceName"]
+                        mm_cluster_id = member_str["clusterId"]
+                        mm_network_partition_id = member_str["networkPartitionId"] if "networkPartitionId" in member_str \
+                            else None
+                        mm_partition_id = member_str["partitionId"] if "partitionId" in member_str else None
+                        mm_cluster_instance_id = member_str["clusterInstanceId"] if "clusterInstanceId" in member_str \
+                            else None
+
+                        member_obj = Member(mm_service_name, mm_cluster_id, mm_network_partition_id,
+                                            mm_partition_id, member_id, mm_cluster_instance_id)
+                        member_obj.member_public_ips = member_str["memberPublicIPs"] if "memberPublicIPs" in member_str \
+                            else None
+                        member_obj.member_default_public_ip = member_str["defaultPublicIP"] \
+                            if "defaultPublicIP" in member_str else None
+                        member_obj.status = member_str["memberStateManager"]["stateStack"][-1]
+                        member_obj.member_private_ips = member_str["memberPrivateIPs"] if "memberPrivateIPs" in member_str \
+                            else None
+                        member_obj.member_default_private_ip = member_str["defaultPrivateIP"] \
+                            if "defaultPrivateIP" in member_str else None
+                        member_obj.properties = member_str["properties"] if "properties" in member_str else None
+                        member_obj.lb_cluster_id = member_str["lbClusterId"] if "lbClusterId" in member_str else None
+                        member_obj.init_time = member_str["initTime"] if "initTime" in member_str else None
+                        member_obj.json_str = member_str
+
+                        # add port map
+                        for mm_port_proxy in member_str["portMap"]:
+                            mm_port_str = member_str["portMap"][mm_port_proxy]
+                            mm_port_obj = Port(mm_port_str["protocol"], mm_port_str["value"], mm_port_proxy)
+                            member_obj.add_port(mm_port_obj)
+                        cluster_obj.add_member(member_obj)
+                    service_obj.add_cluster(cluster_obj)
+                topology_obj.add_service(service_obj)
+            instance.topology = topology_obj
+
+        return instance
+
+    def get_topology(self):
+        return self.topology
+
+
+class MemberStartedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.instance_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+        self.status = None
+        """ :type : str  """
+        self.properties = {}
+        """ :type : dict[str, str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberStartedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.instance_id = json_obj["instanceId"] if "instanceId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+        instance.properties = json_obj["properties"] if "properties" in json_obj else None
+
+        return instance
+
+
+class MemberCreatedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+        self.lb_cluster_id = None
+        """ :type : str  """
+        self.member_public_ips = None
+        """ :type : str  """
+        self.member_private_ips = None
+        """ :type : str  """
+        self.properties = {}
+        """ :type : dict[str, str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberCreatedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+        instance.lb_cluster_id = json_obj["lbClusterId"] if "lbClusterId" in json_obj else None
+        instance.member_private_ips = json_obj["memberPrivateIPs"] if "memberPrivateIPs" in json_obj else None
+        instance.member_public_ips = json_obj["memberPublicIPs"] if "memberPublicIPs" in json_obj else None
+        instance.member_default_public_ip = json_obj["defaultPublicIP"] if "defaultPublicIP" in json_obj else None
+        instance.member_default_private_ip = json_obj["defaultPrivateIP"] if "defaultPrivateIP" in json_obj else None
+        instance.properties = json_obj["properties"]
+
+        return instance
+
+
+class MemberInitializedEvent:
+
+    def __init__(self):
+        self.service_name = None
+        """ :type : str  """
+        self.cluster_id = None
+        """ :type : str  """
+        self.clusterInstanceId = None
+        """ :type : str  """
+        self.member_id = None
+        """ :type : str  """
+        self.network_partition_id = None
+        """ :type : str  """
+        self.partition_id = None
+        """ :type : str  """
+        self.lb_cluster_id = None
+        """ :type : str  """
+        self.member_public_ips = None
+        """ :type : str  """
+        self.member_private_ips = None
+        """ :type : str  """
+        self.properties = {}
+        """ :type : dict[str, str]  """
+
+    @staticmethod
+    def create_from_json(json_str):
+        json_obj = json.loads(json_str)
+        instance = MemberCreatedEvent()
+
+        instance.service_name = json_obj["serviceName"] if "serviceName" in json_obj else None
+        instance.cluster_id = json_obj["clusterId"] if "clusterId" in json_obj else None
+        instance.cluster_instance_id = json_obj["clusterInstanceId"] if "clusterInstanceId" in json_obj else None
+        instance.member_id = json_obj["memberId"] if "memberId" in json_obj else None
+        instance.network_partition_id = json_obj["networkPartitionId"] if "networkPartitionId" in json_obj else None
+        instance.partition_id = json_obj["partitionId"] if "partitionId" in json_obj else None
+        instance.lb_cluster_id = json_obj["lbClusterId"] if "lbClusterId" in json_obj else None
+        instance.member_private_ips = json_obj["memberPrivateIPs"] if "memberPrivateIPs" in json_obj else None
+        instance.member_public_ips = json_obj["memberPublicIPs"] if "memberPublicIPs" in json_obj else None
+        instance.member_default_public_ip = json_obj["defaultPublicIP"] if "defaultPublicIP" in json_obj else None
+        instance.member_default_private_ip = json_obj["defaultPrivateIP"] if "defaultPrivateIP" in json_obj else None
+        instance.properties = json_obj["properties"]
+
+        return instance
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/gitrepositorysynchronizationexception.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/gitrepositorysynchronizationexception.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/gitrepositorysynchronizationexception.py
new file mode 100644
index 0000000..7134f5d
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/gitrepositorysynchronizationexception.py
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class GitRepositorySynchronizationException(Exception):
+    """
+    Exception raised during a git repository related task
+    """
+    __message = None
+
+    def __init__(self, message):
+        Exception.__init__(self, message)
+        self.__message = message
+
+    def get_message(self):
+        """
+        The message provided when the exception is raised
+        :return: message
+        :rtype: str
+        """
+        return self.__message

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/parameternotfoundexception.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/parameternotfoundexception.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/parameternotfoundexception.py
new file mode 100644
index 0000000..7536544
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/parameternotfoundexception.py
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class ParameterNotFoundException(Exception):
+    """
+    Exception raised when a property is not present in the configuration or the payload
+    of the cartridge agent
+    """
+    __message = None
+
+    def __init__(self, message):
+        Exception.__init__(self, message)
+        self.__message = message
+
+    def get_message(self):
+        """
+        The message provided when the exception is raised
+        :return: message
+        :rtype: str
+        """
+        return self.__message

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/thriftreceiverofflineexception.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/thriftreceiverofflineexception.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/thriftreceiverofflineexception.py
new file mode 100644
index 0000000..867f58a
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/exception/thriftreceiverofflineexception.py
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class ThriftReceiverOfflineException(Exception):
+    """
+    Exception raised when the connection to the Thrift receiver is dropped when publishing events
+    """
+    __message = None
+
+    def __init__(self, message):
+        Exception.__init__(self, message)
+        self.__message = message
+
+    def get_message(self):
+        """
+        The message provided when the exception is raised
+        :return: message
+        :rtype: str
+        """
+        return self.__message

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/extensionhandler.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/extensionhandler.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/extensionhandler.py
new file mode 100644
index 0000000..c58d4ef
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/extensions/extensionhandler.py
@@ -0,0 +1,393 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+from ..util import extensionutils, cartridgeagentutils
+
+
+class ExtensionHandler:
+    """
+    Extension execution related logic
+    """
+    log = None
+
+    SUPER_TENANT_ID = -1234
+    SUPER_TENANT_REPO_PATH = "/repository/deployment/server/"
+    TENANT_REPO_PATH = "/repository/tenants/"
+
+    def __init__(self):
+        self.log = LogFactory().get_log(__name__)
+        self.cartridge_agent_config = CartridgeAgentConfiguration()
+
+    def on_instance_started_event(self):
+        self.log.debug("Processing instance started event...")
+        env_params = {}
+        extensionutils.execute_instance_started_extension(env_params)
+
+    def on_instance_activated_event(self):
+        self.log.debug("Processing instance activated event...")
+        env_params = {}
+        extensionutils.execute_instance_activated_extension(env_params)
+
+    def get_repo_path_for_tenant(self, tenant_id, git_local_repo_path, is_multitenant):
+        repo_path = ""
+
+        if is_multitenant:
+            if tenant_id == self.SUPER_TENANT_ID:
+                # super tenant, /repository/deploy/server/
+                super_tenant_repo_path = self.cartridge_agent_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 += self.SUPER_TENANT_REPO_PATH
+
+            else:
+                # normal tenant, /repository/tenants/tenant_id
+                tenant_repo_path = self.cartridge_agent_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 += self.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("Artifact update event received: [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.cartridge_agent_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.cartridge_agent_config.app_path
+
+            repo_password = None
+            if artifacts_updated_event.repo_password is not None:
+                secret = self.cartridge_agent_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.cartridge_agent_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, is_multitenant,
+                                   commit_enabled)
+
+            # checkout code
+            subscribe_run, updated = agentgithandler.AgentGitHandler.checkout(repo_info)
+            # execute artifact updated extension
+            env_params = {"STRATOS_ARTIFACT_UPDATED_CLUSTER_ID": artifacts_updated_event.cluster_id,
+                          "STRATOS_ARTIFACT_UPDATED_TENANT_ID": artifacts_updated_event.tenant_id,
+                          "STRATOS_ARTIFACT_UPDATED_REPO_URL": artifacts_updated_event.repo_url,
+                          "STRATOS_ARTIFACT_UPDATED_REPO_PASSWORD": artifacts_updated_event.repo_password,
+                          "STRATOS_ARTIFACT_UPDATED_REPO_USERNAME": artifacts_updated_event.repo_username,
+                          "STRATOS_ARTIFACT_UPDATED_STATUS": artifacts_updated_event.status}
+
+            extensionutils.execute_artifacts_updated_extension(env_params)
+
+            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.cartridge_agent_config.read_property(cartridgeagentconstants.ENABLE_ARTIFACT_UPDATE,
+                                                                         False)
+            update_artifacts = True if str(update_artifacts).strip().lower() == "true" else False
+            if update_artifacts:
+                auto_commit = self.cartridge_agent_config.is_commits_enabled
+                auto_checkout = self.cartridge_agent_config.is_checkout_enabled
+
+                try:
+                    update_interval = int(self.cartridge_agent_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: %r seconds" % update_interval)
+
+                self.log.info("Auto Commit is turned %r " % ("on" if auto_commit else "off"))
+                self.log.info("Auto Checkout is turned %r " % ("on" if auto_checkout else "off"))
+
+                agentgithandler.AgentGitHandler.schedule_artifact_update_task(
+                    repo_info,
+                    auto_checkout,
+                    auto_commit,
+                    update_interval)
+
+    def on_artifact_update_scheduler_event(self, tenant_id):
+        env_params = {"STRATOS_ARTIFACT_UPDATED_TENANT_ID": str(tenant_id),
+                      "STRATOS_ARTIFACT_UPDATED_SCHEDULER": str(True)}
+
+        extensionutils.execute_artifacts_updated_extension(env_params)
+
+    def on_instance_cleanup_cluster_event(self, instance_cleanup_cluster_event):
+        self.cleanup()
+
+    def on_instance_cleanup_member_event(self, instance_cleanup_member_event):
+        self.cleanup()
+
+    def on_member_activated_event(self, member_activated_event):
+        self.log.info("Member activated event received: [service] %r [cluster] %r [member] %r"
+                      % (member_activated_event.service_name,
+                         member_activated_event.cluster_id,
+                         member_activated_event.member_id))
+
+        member_initialized = extensionutils.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
+
+        extensionutils.execute_member_activated_extension({})
+
+    def on_complete_topology_event(self, complete_topology_event):
+        self.log.debug("Complete topology event received")
+
+        service_name_in_payload = self.cartridge_agent_config.service_name
+        cluster_id_in_payload = self.cartridge_agent_config.cluster_id
+        member_id_in_payload = self.cartridge_agent_config.member_id
+
+        member_initialized = extensionutils.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.cartridge_agent_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)
+
+        env_params = {"STRATOS_TOPOLOGY_JSON": json.dumps(topology.json_str),
+                      "STRATOS_MEMBER_LIST_JSON": json.dumps(cluster.member_list_json)}
+
+        extensionutils.execute_complete_topology_extension(env_params)
+
+    # Member initialized event is sent by cloud controller once volume attachment
+    # and ip address allocation is completed successfully
+    def on_member_initialized_event(self, member_initialized_event):
+        self.log.debug("Member initialized event received")
+
+        service_name_in_payload = self.cartridge_agent_config.service_name
+        cluster_id_in_payload = self.cartridge_agent_config.cluster_id
+        member_id_in_payload = self.cartridge_agent_config.member_id
+
+        member_initialized = extensionutils.check_member_state_in_topology(
+            service_name_in_payload,
+            cluster_id_in_payload,
+            member_id_in_payload)
+
+        if not member_initialized:
+            return
+        else:
+            self.cartridge_agent_config.initialized = True
+
+    def on_complete_tenant_event(self, complete_tenant_event):
+        self.log.debug("Complete tenant event received")
+
+        tenant_list_json = complete_tenant_event.tenant_list_json
+        self.log.debug("Complete tenants:" + json.dumps(tenant_list_json))
+
+        env_params = {"STRATOS_TENANT_LIST_JSON": json.dumps(tenant_list_json)}
+
+        extensionutils.execute_complete_tenant_extension(env_params)
+
+    def on_member_terminated_event(self, member_terminated_event):
+        self.log.info("Member terminated event received: [service] " + member_terminated_event.service_name +
+                      " [cluster] " + member_terminated_event.cluster_id
+                      + " [member] " + member_terminated_event.member_id)
+
+        member_initialized = extensionutils.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
+
+        extensionutils.execute_member_terminated_extension({})
+
+    def on_member_suspended_event(self, member_suspended_event):
+        self.log.info("Member suspended event received: [service] " + member_suspended_event.service_name +
+                      " [cluster] " + member_suspended_event.cluster_id +
+                      " [member] " + member_suspended_event.member_id)
+
+        member_initialized = extensionutils.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
+
+        extensionutils.execute_member_suspended_extension({})
+
+    def on_member_started_event(self, member_started_event):
+        self.log.info("Member started event received: [service] " + member_started_event.service_name +
+                      " [cluster] " + member_started_event.cluster_id + " [member] " + member_started_event.member_id)
+
+        member_initialized = extensionutils.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
+
+        extensionutils.execute_member_started_extension({})
+
+    def start_server_extension(self):
+        service_name_in_payload = self.cartridge_agent_config.service_name
+        cluster_id_in_payload = self.cartridge_agent_config.cluster_id
+        member_id_in_payload = self.cartridge_agent_config.member_id
+
+        topology_consistant = extensionutils.check_member_state_in_topology(service_name_in_payload,
+                                                                            cluster_id_in_payload,
+                                                                            member_id_in_payload)
+
+        if not topology_consistant:
+            self.log.error("Member has not initialized, failed to execute start server event")
+            return
+
+        extensionutils.execute_start_servers_extension({})
+
+    def volume_mount_extension(self, persistence_mappings_payload):
+        extensionutils.execute_volume_mount_extension(persistence_mappings_payload)
+
+    def on_subscription_domain_added_event(self, subscription_domain_added_event):
+        tenant_domain = ExtensionHandler.find_tenant_domain(subscription_domain_added_event.tenant_id)
+        self.log.info(
+            "Subscription domain added event received: [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
+        )
+
+        env_params = {"STRATOS_SUBSCRIPTION_SERVICE_NAME": subscription_domain_added_event.service_name,
+                      "STRATOS_SUBSCRIPTION_DOMAIN_NAME": subscription_domain_added_event.domain_name,
+                      "STRATOS_SUBSCRIPTION_TENANT_ID": int(subscription_domain_added_event.tenant_id),
+                      "STRATOS_SUBSCRIPTION_TENANT_DOMAIN": tenant_domain,
+                      "STRATOS_SUBSCRIPTION_APPLICATION_CONTEXT": subscription_domain_added_event.application_context}
+
+        extensionutils.execute_subscription_domain_added_extension(env_params)
+
+    def on_subscription_domain_removed_event(self, subscription_domain_removed_event):
+        tenant_domain = ExtensionHandler.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
+        )
+
+        env_params = {"STRATOS_SUBSCRIPTION_SERVICE_NAME": subscription_domain_removed_event.service_name,
+                      "STRATOS_SUBSCRIPTION_DOMAIN_NAME": subscription_domain_removed_event.domain_name,
+                      "STRATOS_SUBSCRIPTION_TENANT_ID": int(subscription_domain_removed_event.tenant_id),
+                      "STRATOS_SUBSCRIPTION_TENANT_DOMAIN": tenant_domain}
+
+        extensionutils.execute_subscription_domain_removed_extension(env_params)
+
+    def on_copy_artifacts_extension(self, src, des):
+        extensionutils.execute_copy_artifact_extension(src, des)
+
+    def on_tenant_subscribed_event(self, tenant_subscribed_event):
+        self.log.info(
+            "Tenant subscribed event received: [tenant] " + tenant_subscribed_event.tenant_id +
+            " [service] " + tenant_subscribed_event.service_name + " [cluster] " + tenant_subscribed_event.cluster_ids
+        )
+
+        extensionutils.execute_tenant_subscribed_extension({})
+
+    def on_application_signup_removal_event(self, application_signup_removal_event):
+        self.log.info(
+            "Tenant unsubscribed event received: [tenant] " + application_signup_removal_event.tenantId +
+            " [application ID] " + application_signup_removal_event.applicationId
+        )
+
+        if self.cartridge_agent_config.service_name == application_signup_removal_event.applicationId:
+            agentgithandler.AgentGitHandler.remove_repo(application_signup_removal_event.tenant_id)
+
+        extensionutils.execute_application_signup_removal_extension({})
+
+    def cleanup(self):
+        self.log.info("Executing cleaning up the data in the cartridge instance...")
+
+        cartridgeagentpublisher.publish_maintenance_mode_event()
+
+        extensionutils.execute_cleanup_extension()
+        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()
+
+    @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] %r" % tenant_id)
+
+        return tenant.tenant_domain
+
+from ..artifactmgt.git import agentgithandler
+from ..artifactmgt.repository import Repository
+from ..config.cartridgeagentconfiguration import CartridgeAgentConfiguration
+from ..publisher import cartridgeagentpublisher
+from ..topology.topologycontext import *
+from ..tenant.tenantcontext import *
+from ..util.log import LogFactory

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/__init__.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/__init__.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/abstracthealthstatisticspublisher.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/abstracthealthstatisticspublisher.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/abstracthealthstatisticspublisher.py
new file mode 100644
index 0000000..685344d
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/abstracthealthstatisticspublisher.py
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+class AbstractHealthStatisticsReader:
+    """
+    Abstract class to implement to create a custom health stat reader
+    """
+
+    def stat_cartridge_health(self):
+        """
+        Abstract method that when implemented reads the memory usage and the load average
+        of the instance running the agent and returns a CartridgeHealthStatistics object
+        with the information
+
+        :return: CartridgeHealthStatistics object with memory usage and load average values
+        :rtype : CartridgeHealthStatistics
+        """
+        raise NotImplementedError
+
+
+class CartridgeHealthStatistics:
+    """
+    Holds the memory usage and load average reading
+    """
+
+    def __init__(self):
+        self.memory_usage = None
+        """:type : float"""
+        self.load_avg = None
+        """:type : float"""
+
+
+class CEPPublisherException(Exception):
+    """
+    Exception to be used during CEP publishing operations
+    """
+
+    def __init__(self, msg):
+        super(self,  msg)
+        self.message = msg
+
+    def get_message(self):
+        """
+        The message provided when the exception is raised
+        :return: message
+        :rtype: str
+        """
+        return self.message

http://git-wip-us.apache.org/repos/asf/stratos/blob/b11e4de2/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/healthstats.py
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/healthstats.py b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/healthstats.py
new file mode 100644
index 0000000..9298af1
--- /dev/null
+++ b/components/org.apache.stratos.python.cartridge.agent/src/main/python/cartridge.agent/cartridge.agent/modules/healthstatspublisher/healthstats.py
@@ -0,0 +1,261 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from threading import Thread
+import time
+import psutil
+import os
+import multiprocessing
+
+from abstracthealthstatisticspublisher import *
+from ..databridge.agent import *
+from ..config.cartridgeagentconfiguration import CartridgeAgentConfiguration
+from ..util import cartridgeagentutils, cartridgeagentconstants
+from ..exception.thriftreceiverofflineexception import ThriftReceiverOfflineException
+
+
+class HealthStatisticsPublisherManager(Thread):
+    """
+    Read from an implementation of AbstractHealthStatisticsPublisher the value for memory usage and
+    load average and publishes them as ThriftEvents to a CEP server
+    """
+    STREAM_NAME = "cartridge_agent_health_stats"
+    STREAM_VERSION = "1.0.0"
+    STREAM_NICKNAME = "agent health stats"
+    STREAM_DESCRIPTION = "agent health stats"
+
+    def __init__(self, publish_interval):
+        """
+        Initializes a new HealthStatistsPublisherManager with a given number of seconds as the interval
+        :param int publish_interval: Number of seconds as the interval
+        :return: void
+        """
+        Thread.__init__(self)
+
+        self.log = LogFactory().get_log(__name__)
+
+        self.publish_interval = publish_interval
+        """:type : int"""
+
+        self.terminated = False
+
+        self.publisher = HealthStatisticsPublisher()
+        """:type : HealthStatisticsPublisher"""
+        # TODO: load plugins for the reader
+        self.stats_reader = DefaultHealthStatisticsReader()
+        """:type : AbstractHealthStatisticsReader"""
+
+    def run(self):
+        while not self.terminated:
+            time.sleep(self.publish_interval)
+
+            try:
+                cartridge_stats = self.stats_reader.stat_cartridge_health()
+                self.log.debug("Publishing memory consumption: %r" % cartridge_stats.memory_usage)
+                self.publisher.publish_memory_usage(cartridge_stats.memory_usage)
+
+                self.log.debug("Publishing load average: %r" % cartridge_stats.load_avg)
+                self.publisher.publish_load_average(cartridge_stats.load_avg)
+            except ThriftReceiverOfflineException:
+                self.log.error("Couldn't publish health statistics to CEP. Thrift Receiver offline. Reconnecting...")
+                try:
+                    self.publisher = HealthStatisticsPublisher()
+                except:
+                    self.log.error("Couldn't connect. CEP Offline.")
+
+        self.publisher.publisher.disconnect()
+
+
+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(cartridgeagentconstants.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(cartridgeagentconstants.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)
+
+
+class DefaultHealthStatisticsReader(AbstractHealthStatisticsReader):
+    """
+    Default implementation of the AbstractHealthStatisticsReader
+    """
+
+    def __init__(self):
+        self.log = LogFactory().get_log(__name__)
+
+    def stat_cartridge_health(self):
+        cartridge_stats = CartridgeHealthStatistics()
+        cartridge_stats.memory_usage = DefaultHealthStatisticsReader.__read_mem_usage()
+        cartridge_stats.load_avg = DefaultHealthStatisticsReader.__read_load_avg()
+
+        self.log.debug("Memory read: %r, CPU read: %r" % (cartridge_stats.memory_usage, cartridge_stats.load_avg))
+        return cartridge_stats
+
+    @staticmethod
+    def __read_mem_usage():
+        return psutil.virtual_memory().percent
+
+    @staticmethod
+    def __read_load_avg():
+        (one, five, fifteen) = os.getloadavg()
+        cores = multiprocessing.cpu_count()
+
+        return (one/cores) * 100
+
+
+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(
+           cartridgeagentconstants.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(
+            cartridgeagentconstants.CEP_RECEIVER_IP, False)
+        if self.server_ip is None or self.server_ip.strip() == "":
+            raise RuntimeError("System property not found: " + cartridgeagentconstants.CEP_RECEIVER_IP)
+
+        self.server_port = self.cartridge_agent_config.read_property(
+            cartridgeagentconstants.CEP_RECEIVER_PORT, False)
+        if self.server_port is None or self.server_port.strip() == "":
+            raise RuntimeError("System property not found: " + cartridgeagentconstants.CEP_RECEIVER_PORT)
+
+        self.admin_username = self.cartridge_agent_config.read_property(
+            cartridgeagentconstants.CEP_SERVER_ADMIN_USERNAME, False)
+        if self.admin_username is None or self.admin_username.strip() == "":
+            raise RuntimeError("System property not found: " + cartridgeagentconstants.CEP_SERVER_ADMIN_USERNAME)
+
+        self.admin_password = self.cartridge_agent_config.read_property(
+            cartridgeagentconstants.CEP_SERVER_ADMIN_PASSWORD, False)
+        if self.admin_password is None or self.admin_password.strip() == "":
+            raise RuntimeError("System property not found: " + cartridgeagentconstants.CEP_SERVER_ADMIN_PASSWORD)
+
+        CEPPublisherConfiguration.log.info("CEP Publisher configuration initialized")