Refactored log initializers to Logfactory Added Gittle to be used to clone with authentication Added additional gittle repo object to gitrepository object
Project: http://git-wip-us.apache.org/repos/asf/stratos/repo Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/b1c5d361 Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/b1c5d361 Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/b1c5d361 Branch: refs/heads/master Commit: b1c5d36115dc36938d2b55f8ad33d0c7e498e9cf Parents: fa48ec1 Author: Chamila de Alwis <[email protected]> Authored: Thu Oct 2 14:34:02 2014 +0530 Committer: Chamila de Alwis <[email protected]> Committed: Thu Oct 9 15:40:52 2014 +0530 ---------------------------------------------------------------------- .../cartridge-agent/agent.py | 3 +- .../modules/artifactmgt/git/agentgithandler.py | 197 ++++++++++++++++--- .../modules/artifactmgt/git/gitrepository.py | 7 +- .../config/cartridgeagentconfiguration.py | 4 +- .../extensions/defaultextensionhandler.py | 8 +- .../publisher/cartridgeagentpublisher.py | 3 +- .../modules/subscriber/eventsubscriber.py | 4 +- .../modules/util/cartridgeagentutils.py | 18 +- .../modules/util/extensionutils.py | 4 +- 9 files changed, 200 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/agent.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/agent.py b/tools/python-cartridge-agent/cartridge-agent/agent.py index 5ae7664..bf47397 100644 --- a/tools/python-cartridge-agent/cartridge-agent/agent.py +++ b/tools/python-cartridge-agent/cartridge-agent/agent.py @@ -17,8 +17,7 @@ from modules.datapublisher.logpublisher import * class CartridgeAgent(threading.Thread): - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - log = logging.getLogger(__name__) + log = LogFactory().get_log(__name__) def __init__(self): threading.Thread.__init__(self) http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/agentgithandler.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/agentgithandler.py b/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/agentgithandler.py index e433e0b..e6fd98e 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/agentgithandler.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/agentgithandler.py @@ -1,7 +1,9 @@ import logging from threading import current_thread, Thread - +import os from git import * +from gittle import Gittle, GittleAuth # GitPython and Gittle are both used at the time being for pros and cons of both +import urllib2 from gitrepository import GitRepository from ... config.cartridgeagentconfiguration import CartridgeAgentConfiguration @@ -9,23 +11,42 @@ from ... util import cartridgeagentutils, extensionutils, cartridgeagentconstant from ... util.asyncscheduledtask import AsyncScheduledTask from ... artifactmgt.repositoryinformation import RepositoryInformation from ... extensions.abstractextensionhandler import AbstractExtensionHandler +from ... util.log import LogFactory + class AgentGitHandler: - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - log = logging.getLogger(__name__) + """ + Handles all the git artifact management tasks related to a cartridge + """ + + log = LogFactory().get_log(__name__) SUPER_TENANT_ID = -1234 SUPER_TENANT_REPO_PATH = "/repository/deployment/server/" TENANT_REPO_PATH = "/repository/tenants/" - extension_handler = AbstractExtensionHandler() + extension_handler = AbstractExtensionHandler() # TODO: remove dependancy __git_repositories = {} # (tenant_id => gitrepository.GitRepository) @staticmethod def checkout(repo_info): + """ + Checks out the code from the remote repository. + If local repository path is empty, a clone operation is done. + If there is a cloned repository already on the local repository path, a pull operation + will be performed. + If there are artifacts not in the repository already on the local repository path, + they will be added to a git repository, the remote url added as origin, and then + a pull operation will be performed. + + :param RepositoryInformation repo_info: The repository information object + :return: A tuple containing whether it was an initial clone or not, and the repository + context object + :rtype: tuple(bool, GitRepository) + """ repo_context = AgentGitHandler.get_repo_context(repo_info.tenant_id) if repo_context is not None: #has been previously cloned, this is not the subscription run @@ -48,7 +69,7 @@ class AgentGitHandler: subscribe_run = True repo_context = AgentGitHandler.clone(repo_context) - return {"subscribe_run": subscribe_run, "repo_context": repo_context} + return subscribe_run, repo_context @staticmethod def sync_initial_local_artifacts(repo_context): @@ -75,8 +96,7 @@ class AgentGitHandler: @staticmethod def init(path): try: - repo = Repo.init(path, mkdir=True) - repo.git.init() + repo = Gittle.init(path) except: AgentGitHandler.log.exception("Initializing local repo at %r failed" % path) raise Exception("Initializing local repo at %r failed" % path) @@ -90,7 +110,6 @@ class AgentGitHandler: try: ref._get_object() except ValueError: - #corrupt sha in the reference return False return True @@ -157,7 +176,6 @@ class AgentGitHandler: @staticmethod def clone(repo_info): - #TODO: credential management repo_context = None try: repo_context = AgentGitHandler.create_git_repo_context(repo_info) @@ -165,23 +183,76 @@ class AgentGitHandler: if not os.path.isdir(repo_context.local_repo_path): cartridgeagentutils.create_dir(repo_context.local_repo_path) - repo = Repo.clone_from(repo_context.repo_url, repo_context.local_repo_path) + auth = AgentGitHandler.create_auth_configuration(repo_context) + + if auth is not None: + # authentication is required, use Gittle + gittle_repo = Gittle.clone(repo_context.repo_url, repo_context.local_repo_path, auth=auth) + repo = Repo(repo_context.local_repo_path) + else: + # authentication is not required, use GitPython + repo = Repo.clone_from(repo_context.repo_url, repo_context.local_repo_path) + gittle_repo = Gittle(repo_context.local_repo_path) repo_context.cloned = True - repo_context.repo = repo + repo_context.gittle_repo = gittle_repo + repo_context.repo = repo AgentGitHandler.add_repo_context(repo_context) AgentGitHandler.log.info("Git clone operation for tenant %r successful" % repo_context.tenant_id) - except GitCommandError as ex: - if "remote: Repository not found." in ex: - AgentGitHandler.log.exception("Accessing remote git repository failed for tenant %r" % repo_context.tenant_id) - #GitPython deletes the target folder if remote not found - cartridgeagentutils.create_dir(repo_context.local_repo_path) - else: - AgentGitHandler.log.exception("Git clone operation for tenant %r failed" % repo_context.tenant_id) + except urllib2.URLError: + AgentGitHandler.log.exception("Accessing remote git repository failed for tenant %r" % repo_context.tenant_id) + except OSError: + AgentGitHandler.log.exception("Permission denied for repository path for tenant %r" % repo_context.tenant_id) + except: + AgentGitHandler.log.exception("Git clone operation for tenant %r failed" % repo_context.tenant_id) finally: return repo_context @staticmethod + def create_auth_configuration(repo_context): + """ + Creates a GittleAuth object based on the type of authorization + :param GitRepository repo_context: The repository context object + :return: GittleAuth object or None if no authorization needed + :rtype: GittleAuth + """ + if repo_context.key_based_auth: + pkey = AgentGitHandler.get_private_key() + auth = GittleAuth(pkey=pkey) + elif repo_context.repo_username.strip() != "" and repo_context.repo_password.strip() != "": + auth = GittleAuth(username=repo_context.repo_username, password=repo_context.repo_password) + else: + auth = None + + return auth + + @staticmethod + def get_private_key(): + """ + Returns a file handler to the private key path specified by Carbon or default if not specified + by Carbon + :return: The file object of the private key file + :rtype: file + """ + pkey_name = cartridgeagentutils.get_carbon_server_property("SshPrivateKeyName") + if pkey_name is None: + pkey_name = "wso2" + + pkey_path = cartridgeagentutils.get_carbon_server_property("SshPrivateKeyPath") + if pkey_path is None: + pkey_path = os.environ["HOME"] + "/.ssh" + + if pkey_path.endswith("/"): + pkey_ptr = pkey_path + pkey_name + else: + pkey_ptr = pkey_path + "/" + pkey_name + + pkey_file = open(pkey_ptr) + + return pkey_file + + + @staticmethod def add_repo_context(repo_context): AgentGitHandler.__git_repositories[repo_context.tenant_id] = repo_context @@ -215,22 +286,39 @@ class AgentGitHandler: repo_context.is_multitenant = repo_info.is_multitenant repo_context.commit_enabled = repo_info.commit_enabled - # TODO: push - # push not implemented - # if is_key_based_auth(repo_info.repo_url, tenant_id): - # repo.key_based_auth = True - # init_ssh_auth() - # else: - # repo.key_based_auth = False + if AgentGitHandler.is_key_based_auth(repo_info.repo_url, repo_info.tenant_id): + repo_context.key_based_auth = True + else: + repo_context.key_based_auth = False repo_context.cloned = False repo_context.repo = None + repo_context.gittle_repo = None return repo_context - # @staticmethod - # def is_key_based_auth(repo_url, tenant_id): + @staticmethod + def is_key_based_auth(repo_url, tenant_id): + """ + Checks if the given git repo has key based authentication + :param str repo_url: Git repository remote url + :param str tenant_id: Tenant ID + :return: True if key based, False otherwise + :rtype: bool + """ + if repo_url.startswith("http://") or repo_url.startswith("https://"): + # username and password, not key based + return False + elif repo_url.startswith("git://github.com"): + # no auth required + return False + elif repo_url.startswith("ssh://") or "@" in repo_url: + # key based + return True + else: + AgentGitHandler.log.error("Invalid git URL provided for tenant " + tenant_id) + raise RuntimeError("Invalid git URL provided for tenant " + tenant_id) @staticmethod def get_repo_path_for_tenant(tenant_id, git_local_repo_path, is_multitenant): @@ -278,6 +366,58 @@ class AgentGitHandler: @staticmethod def commit(repo_info): + """ + Commits and pushes new artifacts to the remote repository + :param repo_info: + :return: + """ + tenant_id = repo_info.tenant_id + repo_context = AgentGitHandler.get_repo_context(tenant_id) + gittle_repo = repo_context.gittle_repo + try: + modified = True if gittle_repo.modified_unstaged_files.count > 0 else False + except OSError: + # removed files + modified = True + + if not modified: + AgentGitHandler.log.debug("No changes detected in the local repository for tenant " + tenant_id) + return + + gittle_repo.stage(gittle_repo.untracked_files) + gittle_repo.stage(gittle_repo.removed_files) + gittle_repo.stage(gittle_repo.modified_unstaged_files) + + #commit to local repositpory + commit_message = "tenant " + tenant_id + "'s artifacts committed to local repo at " + repo_context.local_repo_path + + try: + commit_hash = gittle_repo.commit(name="First Author", email="[email protected]", message=commit_message) + AgentGitHandler.log.debug("Committed artifacts for tenant : " + tenant_id + " : " + commit_hash) + except: + AgentGitHandler.log.exception("Committing artifacts to local repository failed for tenant " + tenant_id) + + #push to remote + try: + repo = repo_context.repo + #TODO: check key based authentication + credentialed_remote_url = AgentGitHandler.get_credentialed_remote_url(repo_context) + push_remote = repo.create_remote('push_remote', credentialed_remote_url) + push_remote.push() + AgentGitHandler.log.debug("Pushed artifacts for tenant : " + tenant_id) + except: + AgentGitHandler.log.exception("Pushing artifacts to remote repository failed for tenant " + tenant_id) + + @staticmethod + def get_credentialed_remote_url(repo_context): + """ + Creates a remote url including the credentials + :param repo_context: + :return: + """ + username = repo_context.repo_username + password = repo_context.repo_password + raise NotImplementedError @staticmethod @@ -326,8 +466,7 @@ class AgentGitHandler: class ArtifactUpdateTask(Thread): def __init__(self, repo_info, auto_checkout, auto_commit): - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - self.log = logging.getLogger(__name__) + self.log = LogFactory().get_log(__name__) Thread.__init__(self) self.repo_info = repo_info self.auto_checkout = auto_checkout http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/gitrepository.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/gitrepository.py b/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/gitrepository.py index ba9d3d7..b7445d5 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/gitrepository.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/artifactmgt/git/gitrepository.py @@ -1,5 +1,6 @@ from ...util.asyncscheduledtask import AsyncScheduledTask - +from gittle import Gittle +from git import * class GitRepository: """ @@ -14,7 +15,9 @@ class GitRepository: self.cloned = False """ :type : bool """ self.repo = None - """ :type : str """ + """ :type : git.repo.base.Repo """ + self.gittle_repo = None + """ :type : gittle.gittle.Gittle """ self.tenant_id = None """ :type : int """ self.key_based_auth = False http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/config/cartridgeagentconfiguration.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/config/cartridgeagentconfiguration.py b/tools/python-cartridge-agent/cartridge-agent/modules/config/cartridgeagentconfiguration.py index 3170e3d..c0e5ea6 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/config/cartridgeagentconfiguration.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/config/cartridgeagentconfiguration.py @@ -3,6 +3,7 @@ import logging import os from ..util import cartridgeagentconstants +from ..util.log import LogFactory from ..exception.parameternotfoundexception import ParameterNotFoundException @@ -11,8 +12,7 @@ class CartridgeAgentConfiguration: Handles the configuration information of the particular Cartridge Agent """ # set log level - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - log = logging.getLogger(__name__) + log = LogFactory().get_log(__name__) payload_params = {} properties = None http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/extensions/defaultextensionhandler.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/extensions/defaultextensionhandler.py b/tools/python-cartridge-agent/cartridge-agent/modules/extensions/defaultextensionhandler.py index 2687687..8005a7a 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/extensions/defaultextensionhandler.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/extensions/defaultextensionhandler.py @@ -9,6 +9,7 @@ from ..publisher import cartridgeagentpublisher from ..exception.parameternotfoundexception import ParameterNotFoundException from ..topology.topologycontext import * from ..tenant.tenantcontext import * +from ..util.log import LogFactory from abstractextensionhandler import AbstractExtensionHandler @@ -19,8 +20,7 @@ class DefaultExtensionHandler(AbstractExtensionHandler): log = None def __init__(self): - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - self.log = logging.getLogger(__name__) + self.log = LogFactory().get_log(__name__) self.wk_members = [] def on_instance_started_event(self): @@ -66,7 +66,7 @@ class DefaultExtensionHandler(AbstractExtensionHandler): is_multitenant, commit_enabled) # checkout code - checkout_result = AgentGitHandler.checkout(repo_info) + subscribe_run, repo_context = AgentGitHandler.checkout(repo_info) # repo_context = checkout_result["repo_context"] # execute artifact updated extension env_params = {"STRATOS_ARTIFACT_UPDATED_CLUSTER_ID": artifacts_updated_event.cluster_id, @@ -78,7 +78,7 @@ class DefaultExtensionHandler(AbstractExtensionHandler): extensionutils.execute_artifacts_updated_extension(env_params) - if checkout_result["subscribe_run"]: + if subscribe_run: # publish instanceActivated cartridgeagentpublisher.publish_instance_activated_event() http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/publisher/cartridgeagentpublisher.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/publisher/cartridgeagentpublisher.py b/tools/python-cartridge-agent/cartridge-agent/modules/publisher/cartridgeagentpublisher.py index 0427e46..260d67d 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/publisher/cartridgeagentpublisher.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/publisher/cartridgeagentpublisher.py @@ -9,8 +9,7 @@ from .. healthstatspublisher.healthstats import * from .. healthstatspublisher.abstracthealthstatisticspublisher import * -logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') -log = logging.getLogger(__name__) +log = LogFactory().get_log(__name__) started = False activated = False http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/subscriber/eventsubscriber.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/subscriber/eventsubscriber.py b/tools/python-cartridge-agent/cartridge-agent/modules/subscriber/eventsubscriber.py index ad32180..a8209a5 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/subscriber/eventsubscriber.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/subscriber/eventsubscriber.py @@ -4,6 +4,7 @@ import paho.mqtt.client as mqtt from .. util import cartridgeagentconstants from .. config.cartridgeagentconfiguration import CartridgeAgentConfiguration +from .. util.log import LogFactory class EventSubscriber(threading.Thread): @@ -18,8 +19,7 @@ class EventSubscriber(threading.Thread): #{"ArtifactUpdateEvent" : onArtifactUpdateEvent()} self.__event_handlers = {} - logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') - self.log = logging.getLogger(__name__) + self.log = LogFactory().get_log(__name__) self.__mb_client = None http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/util/cartridgeagentutils.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/util/cartridgeagentutils.py b/tools/python-cartridge-agent/cartridge-agent/modules/util/cartridgeagentutils.py index efff3ec..d9916da 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/util/cartridgeagentutils.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/util/cartridgeagentutils.py @@ -8,11 +8,11 @@ import shutil from .. config.cartridgeagentconfiguration import CartridgeAgentConfiguration import cartridgeagentconstants +from log import LogFactory unpad = lambda s: s[0:-ord(s[-1])] -logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') -log = logging.getLogger(__name__) +log = LogFactory().get_log(__name__) current_milli_time = lambda: int(round(time.time() * 1000)) @@ -148,4 +148,16 @@ def validate_tenant_range(tenant_range): valid = True if not valid: - raise RuntimeError("Tenant range %r is not valid" % tenant_range) \ No newline at end of file + raise RuntimeError("Tenant range %r is not valid" % tenant_range) + + +def get_carbon_server_property(property_key): + """ + Reads the carbon.xml file and returns the value for the property key. + TODO: Get carbon server xml location + :param str property_key: Property key to look for + :return: The value of the property, None if the property key is invalid or not present + :rtype : str + """ + + raise NotImplementedError \ No newline at end of file http://git-wip-us.apache.org/repos/asf/stratos/blob/b1c5d361/tools/python-cartridge-agent/cartridge-agent/modules/util/extensionutils.py ---------------------------------------------------------------------- diff --git a/tools/python-cartridge-agent/cartridge-agent/modules/util/extensionutils.py b/tools/python-cartridge-agent/cartridge-agent/modules/util/extensionutils.py index 8ce36ba..a694ff1 100644 --- a/tools/python-cartridge-agent/cartridge-agent/modules/util/extensionutils.py +++ b/tools/python-cartridge-agent/cartridge-agent/modules/util/extensionutils.py @@ -5,9 +5,9 @@ import time from .. config.cartridgeagentconfiguration import CartridgeAgentConfiguration from .. topology.topologycontext import * +from log import LogFactory -logging.basicConfig(level=logging.DEBUG, filename='/tmp/cartridge-agent.log') -log = logging.getLogger(__name__) +log = LogFactory().get_log(__name__) def execute_copy_artifact_extension(source, destination):
