{"action":"created","comment":{"url":"https://api.github.com/repos/pulp/pulp/pulls/comments/71977122","id":71977122,"diff_hunk":"@@ -0,0 +1,165 @@\n+import logging\n+import os\n+\n+_LOG = logging.getLogger(__name__)\n+\n+\n+class OneOfValidation(object):\n+    \"\"\"\n+    Validates that the the value is one of possible values\n+    \"\"\"\n+    def __init__(self, values):\n+        self.values = values\n+\n+    def __call__(self, value, config):\n+        if value in self.values:\n+            return (True, None)\n+        else:\n+            return (False, self._err(value))\n+\n+    def _err(self, value):\n+        values_str = \", \".join(self.values)\n+        return \"{value} is not in allowed values: {allowed}\" % (value, values_str)\n+\n+\n+class NonEmptyValidation(object):\n+    \"\"\"\n+    Validates that the value is not None\n+    \"\"\"\n+    def __call__(self, value, config):\n+        if value:\n+            return (True, None)\n+        else:\n+            return (False, self._err(value))\n+\n+    def _err(self, value):\n+        return \"attribute cannot be empty\"\n+\n+\n+class TypeValidation(object):\n+    \"\"\"\n+    Validates that the value is one of allowed types\n+    \"\"\"\n+    def __init__(self, allowed_types):\n+        self.allowed_types = allowed_types\n+\n+    def __call__(self, value, config):\n+        if [True for _type in self.allowed_types if issubclass(type(value), _type)]:\n+            return (True, None)\n+        else:\n+            return (False, self._err(value))\n+\n+    def _err(self, value):\n+        str_types = \", \".join(self.allowed_types)\n+        return \"type of atribute(%s) is not in allowed types: %s\" % (type(value), str_types)\n+\n+\n+class RequireOptionalIf(object):\n+    \"\"\"\n+    Validates that if a particular config is present, other configs that are needed for it are also\n+    present.\n+    \"\"\"\n+    def __init__(self, required_for_attr, condition):\n+        self.required_for_attr = required_for_attr\n+        self.condition = condition\n+\n+    def __call__(self, value, config):\n+        subconfig = config\n+        path = []\n+        if not self.condition(value):\n+            return (True, None)\n+\n+        if isinstance(self.required_for_attr, list):\n+            fifo = [(x, subconfig, path) for x in self.required_for_attr]\n+        elif isinstance(self.required_for_attr, dict):\n+            fifo = [(val, subconfig.get(key), [key])\n+                    for key, val in self.required_for_attr.iteritems()]\n+        while fifo:\n+            (required_for_attr, subconfig, path) = fifo.pop(0)\n+            if isinstance(required_for_attr, list):\n+                for x in required_for_attr:\n+                    fifo.insert(0, (x, subconfig, path))\n+            elif isinstance(required_for_attr, dict):\n+                for key, val in required_for_attr.iteritems():\n+                    fifo.insert(0, (val, subconfig.get(key)), path + [key])\n+            elif isinstance(required_for_attr, basestring):\n+                if required_for_attr not in subconfig:\n+                    return (False, self._err(path + [required_for_attr]))\n+        return (True, None)\n+\n+    def _err(self, path):\n+        return \"%s attribute is required\" % (\"::\".join(path))\n+\n+\n+class RelativePathValidation(object):\n+    \"\"\"\n+    Validates that a path does not start with a forward slash.\n+    \"\"\"\n+    def __call__(self, value, config):\n+        if os.path.isabs(value):\n+            return (False, self._err(value))\n+        else:\n+            return (True, None)\n+\n+    def _err(self, value):\n+        return \"attribute cannot start with a /\"\n+\n+REMOTE_MANDATORY_KEYS = {\n+    \"auth_type\": [OneOfValidation([\"publickey\", \"password\"]),\n+                  RequireOptionalIf({\"remote\": [\"ssh_password\", \"ssh_user\"]},\n+                                    lambda x: x == \"password\"),\n+                  RequireOptionalIf({\"remote\": [\"ssh_identity_file\", \"ssh_user\"]},\n+                                    lambda x: x == \"publickey\")],\n+    \"host\": [TypeValidation([basestring]), NonEmptyValidation()],\n+    \"root\": [TypeValidation([basestring]), NonEmptyValidation()]\n+}\n+\n+REMOTE_OPTIONAL_KEYS = {\n+    \"remote_units_path\": [TypeValidation([basestring]), RelativePathValidation()],\n+    \"ssh_identity_file\": [TypeValidation([basestring]), NonEmptyValidation()],\n+    \"ssh_user\": [TypeValidation([basestring]), NonEmptyValidation()],\n+    \"ssh_password\": [TypeValidation([basestring]), NonEmptyValidation()]\n+}\n+\n+\n+def validate_config(repo, config, config_conduit):\n+    \"\"\"\n+    Validate the prospective configuration instance for the given repository.\n+\n+    :param repo: repository to validate the config for\n+    :type  repo: pulp.plugins.model.Repository\n+    :param config: configuration instance to validate\n+    :type  config: pulp.plugins.config.PluginCallConfiguration\n+    :param config_conduit: conduit providing access to relevant Pulp functionality\n+    :type  config_conduit: pulp.plugins.conduits.repo_config.RepoConfigConduit\n+    :return: tuple of (bool, str) stating that the configuration is valid or not and why\n+    :rtype:  tuple of (bool, str or None)\n+    \"\"\"\n+    _config = config.flatten()  # now config is {}\n+    err_list = []\n+    crit_fail = False\n+    if \"remote\" not in _config or (\"remote\" in _config and not isinstance(_config[\"remote\"], dict)):\n+        err_list.append(\"'remote' dict missing in distributor's configuration\")\n+        crit_fail = True\n+    if not crit_fail:\n+        missing_attr_tmpl = \"'%s' missing in 'remote' section of distributor's configuration\"\n+        for attr, validations in REMOTE_MANDATORY_KEYS.iteritems():\n+            if attr not in _config[\"remote\"]:\n+                err_list.append(missing_attr_tmpl % attr)\n+                continue\n+            for validation in validations:\n+                succeed, _err = validation(_config[\"remote\"][attr], _config)\n+                if not succeed:\n+","path":"server/pulp/plugins/rsync/configuration.py","position":153,"original_position":153,"commit_id":"480b75b8d60785bfb80548374749de7ce8a08398","original_commit_id":"480b75b8d60785bfb80548374749de7ce8a08398","user":{"login":"dkliban","id":294339,"avatar_url":"https://avatars.githubusercontent.com/u/294339?v=3","gravatar_id":"","url":"https://api.github.com/users/dkliban","html_url":"https://github.com/dkliban","followers_url":"https://api.github.com/users/dkliban/followers","following_url":"https://api.github.com/users/dkliban/following{/other_user}","gists_url":"https://api.github.com/users/dkliban/gists{/gist_id}","starred_url":"https://api.github.com/users/dkliban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkliban/subscriptions","organizations_url":"https://api.github.com/users/dkliban/orgs","repos_url":"https://api.github.com/users/dkliban/repos","events_url":"https://api.github.com/users/dkliban/events{/privacy}","received_events_url":"https://api.github.com/users/dkliban/received_events","type":"User","site_admin":false},"body":"removed it","created_at":"2016-07-23T19:33:22Z","updated_at":"2016-07-23T19:33:22Z","html_url":"https://github.com/pulp/pulp/pull/2624#discussion_r71977122","pull_request_url":"https://api.github.com/repos/pulp/pulp/pulls/2624","_links":{"self":{"href":"https://api.github.com/repos/pulp/pulp/pulls/comments/71977122"},"html":{"href":"https://github.com/pulp/pulp/pull/2624#discussion_r71977122"},"pull_request":{"href":"https://api.github.com/repos/pulp/pulp/pulls/2624"}}},"pull_request":{"url":"https://api.github.com/repos/pulp/pulp/pulls/2624","id":76483233,"html_url":"https://github.com/pulp/pulp/pull/2624","diff_url":"https://github.com/pulp/pulp/pull/2624.diff","patch_url":"https://github.com/pulp/pulp/pull/2624.patch","issue_url":"https://api.github.com/repos/pulp/pulp/issues/2624","number":2624,"state":"open","locked":false,"title":"Adds rsync distributor publish steps to platform","user":{"login":"dkliban","id":294339,"avatar_url":"https://avatars.githubusercontent.com/u/294339?v=3","gravatar_id":"","url":"https://api.github.com/users/dkliban","html_url":"https://github.com/dkliban","followers_url":"https://api.github.com/users/dkliban/followers","following_url":"https://api.github.com/users/dkliban/following{/other_user}","gists_url":"https://api.github.com/users/dkliban/gists{/gist_id}","starred_url":"https://api.github.com/users/dkliban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkliban/subscriptions","organizations_url":"https://api.github.com/users/dkliban/orgs","repos_url":"https://api.github.com/users/dkliban/repos","events_url":"https://api.github.com/users/dkliban/events{/privacy}","received_events_url":"https://api.github.com/users/dkliban/received_events","type":"User","site_admin":false},"body":"This adds shared rsync distributor code. The classes provided need to be extended in each plugin that implements the rsync distributor.","created_at":"2016-07-06T18:56:38Z","updated_at":"2016-07-23T19:33:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b3f4be5f8885af4e23a3d55e759158aef1d382d4","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/pulp/pulp/pulls/2624/commits","review_comments_url":"https://api.github.com/repos/pulp/pulp/pulls/2624/comments","review_comment_url":"https://api.github.com/repos/pulp/pulp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pulp/pulp/issues/2624/comments","statuses_url":"https://api.github.com/repos/pulp/pulp/statuses/480b75b8d60785bfb80548374749de7ce8a08398","head":{"label":"dkliban:rsync-distributor","ref":"rsync-distributor","sha":"480b75b8d60785bfb80548374749de7ce8a08398","user":{"login":"dkliban","id":294339,"avatar_url":"https://avatars.githubusercontent.com/u/294339?v=3","gravatar_id":"","url":"https://api.github.com/users/dkliban","html_url":"https://github.com/dkliban","followers_url":"https://api.github.com/users/dkliban/followers","following_url":"https://api.github.com/users/dkliban/following{/other_user}","gists_url":"https://api.github.com/users/dkliban/gists{/gist_id}","starred_url":"https://api.github.com/users/dkliban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkliban/subscriptions","organizations_url":"https://api.github.com/users/dkliban/orgs","repos_url":"https://api.github.com/users/dkliban/repos","events_url":"https://api.github.com/users/dkliban/events{/privacy}","received_events_url":"https://api.github.com/users/dkliban/received_events","type":"User","site_admin":false},"repo":{"id":25177116,"name":"pulp","full_name":"dkliban/pulp","owner":{"login":"dkliban","id":294339,"avatar_url":"https://avatars.githubusercontent.com/u/294339?v=3","gravatar_id":"","url":"https://api.github.com/users/dkliban","html_url":"https://github.com/dkliban","followers_url":"https://api.github.com/users/dkliban/followers","following_url":"https://api.github.com/users/dkliban/following{/other_user}","gists_url":"https://api.github.com/users/dkliban/gists{/gist_id}","starred_url":"https://api.github.com/users/dkliban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkliban/subscriptions","organizations_url":"https://api.github.com/users/dkliban/orgs","repos_url":"https://api.github.com/users/dkliban/repos","events_url":"https://api.github.com/users/dkliban/events{/privacy}","received_events_url":"https://api.github.com/users/dkliban/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dkliban/pulp","description":"Repository for Pulp platform code, including the server and base admin and consumer clients","fork":true,"url":"https://api.github.com/repos/dkliban/pulp","forks_url":"https://api.github.com/repos/dkliban/pulp/forks","keys_url":"https://api.github.com/repos/dkliban/pulp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dkliban/pulp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dkliban/pulp/teams","hooks_url":"https://api.github.com/repos/dkliban/pulp/hooks","issue_events_url":"https://api.github.com/repos/dkliban/pulp/issues/events{/number}","events_url":"https://api.github.com/repos/dkliban/pulp/events","assignees_url":"https://api.github.com/repos/dkliban/pulp/assignees{/user}","branches_url":"https://api.github.com/repos/dkliban/pulp/branches{/branch}","tags_url":"https://api.github.com/repos/dkliban/pulp/tags","blobs_url":"https://api.github.com/repos/dkliban/pulp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dkliban/pulp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dkliban/pulp/git/refs{/sha}","trees_url":"https://api.github.com/repos/dkliban/pulp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dkliban/pulp/statuses/{sha}","languages_url":"https://api.github.com/repos/dkliban/pulp/languages","stargazers_url":"https://api.github.com/repos/dkliban/pulp/stargazers","contributors_url":"https://api.github.com/repos/dkliban/pulp/contributors","subscribers_url":"https://api.github.com/repos/dkliban/pulp/subscribers","subscription_url":"https://api.github.com/repos/dkliban/pulp/subscription","commits_url":"https://api.github.com/repos/dkliban/pulp/commits{/sha}","git_commits_url":"https://api.github.com/repos/dkliban/pulp/git/commits{/sha}","comments_url":"https://api.github.com/repos/dkliban/pulp/comments{/number}","issue_comment_url":"https://api.github.com/repos/dkliban/pulp/issues/comments{/number}","contents_url":"https://api.github.com/repos/dkliban/pulp/contents/{+path}","compare_url":"https://api.github.com/repos/dkliban/pulp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dkliban/pulp/merges","archive_url":"https://api.github.com/repos/dkliban/pulp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dkliban/pulp/downloads","issues_url":"https://api.github.com/repos/dkliban/pulp/issues{/number}","pulls_url":"https://api.github.com/repos/dkliban/pulp/pulls{/number}","milestones_url":"https://api.github.com/repos/dkliban/pulp/milestones{/number}","notifications_url":"https://api.github.com/repos/dkliban/pulp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dkliban/pulp/labels{/name}","releases_url":"https://api.github.com/repos/dkliban/pulp/releases{/id}","deployments_url":"https://api.github.com/repos/dkliban/pulp/deployments","created_at":"2014-10-13T20:47:13Z","updated_at":"2015-04-03T14:29:06Z","pushed_at":"2016-07-22T19:21:55Z","git_url":"git://github.com/dkliban/pulp.git","ssh_url":"git@github.com:dkliban/pulp.git","clone_url":"https://github.com/dkliban/pulp.git","svn_url":"https://github.com/dkliban/pulp","homepage":"","size":91836,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"pulp:master","ref":"master","sha":"37b3ff4e733a711f3364a0fb88dc8b3d022a36a6","user":{"login":"pulp","id":2103606,"avatar_url":"https://avatars.githubusercontent.com/u/2103606?v=3","gravatar_id":"","url":"https://api.github.com/users/pulp","html_url":"https://github.com/pulp","followers_url":"https://api.github.com/users/pulp/followers","following_url":"https://api.github.com/users/pulp/following{/other_user}","gists_url":"https://api.github.com/users/pulp/gists{/gist_id}","starred_url":"https://api.github.com/users/pulp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulp/subscriptions","organizations_url":"https://api.github.com/users/pulp/orgs","repos_url":"https://api.github.com/users/pulp/repos","events_url":"https://api.github.com/users/pulp/events{/privacy}","received_events_url":"https://api.github.com/users/pulp/received_events","type":"Organization","site_admin":false},"repo":{"id":5314652,"name":"pulp","full_name":"pulp/pulp","owner":{"login":"pulp","id":2103606,"avatar_url":"https://avatars.githubusercontent.com/u/2103606?v=3","gravatar_id":"","url":"https://api.github.com/users/pulp","html_url":"https://github.com/pulp","followers_url":"https://api.github.com/users/pulp/followers","following_url":"https://api.github.com/users/pulp/following{/other_user}","gists_url":"https://api.github.com/users/pulp/gists{/gist_id}","starred_url":"https://api.github.com/users/pulp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulp/subscriptions","organizations_url":"https://api.github.com/users/pulp/orgs","repos_url":"https://api.github.com/users/pulp/repos","events_url":"https://api.github.com/users/pulp/events{/privacy}","received_events_url":"https://api.github.com/users/pulp/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pulp/pulp","description":"Repository for Pulp platform code, including the server and base admin and consumer clients","fork":false,"url":"https://api.github.com/repos/pulp/pulp","forks_url":"https://api.github.com/repos/pulp/pulp/forks","keys_url":"https://api.github.com/repos/pulp/pulp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pulp/pulp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pulp/pulp/teams","hooks_url":"https://api.github.com/repos/pulp/pulp/hooks","issue_events_url":"https://api.github.com/repos/pulp/pulp/issues/events{/number}","events_url":"https://api.github.com/repos/pulp/pulp/events","assignees_url":"https://api.github.com/repos/pulp/pulp/assignees{/user}","branches_url":"https://api.github.com/repos/pulp/pulp/branches{/branch}","tags_url":"https://api.github.com/repos/pulp/pulp/tags","blobs_url":"https://api.github.com/repos/pulp/pulp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pulp/pulp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pulp/pulp/git/refs{/sha}","trees_url":"https://api.github.com/repos/pulp/pulp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pulp/pulp/statuses/{sha}","languages_url":"https://api.github.com/repos/pulp/pulp/languages","stargazers_url":"https://api.github.com/repos/pulp/pulp/stargazers","contributors_url":"https://api.github.com/repos/pulp/pulp/contributors","subscribers_url":"https://api.github.com/repos/pulp/pulp/subscribers","subscription_url":"https://api.github.com/repos/pulp/pulp/subscription","commits_url":"https://api.github.com/repos/pulp/pulp/commits{/sha}","git_commits_url":"https://api.github.com/repos/pulp/pulp/git/commits{/sha}","comments_url":"https://api.github.com/repos/pulp/pulp/comments{/number}","issue_comment_url":"https://api.github.com/repos/pulp/pulp/issues/comments{/number}","contents_url":"https://api.github.com/repos/pulp/pulp/contents/{+path}","compare_url":"https://api.github.com/repos/pulp/pulp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pulp/pulp/merges","archive_url":"https://api.github.com/repos/pulp/pulp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pulp/pulp/downloads","issues_url":"https://api.github.com/repos/pulp/pulp/issues{/number}","pulls_url":"https://api.github.com/repos/pulp/pulp/pulls{/number}","milestones_url":"https://api.github.com/repos/pulp/pulp/milestones{/number}","notifications_url":"https://api.github.com/repos/pulp/pulp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pulp/pulp/labels{/name}","releases_url":"https://api.github.com/repos/pulp/pulp/releases{/id}","deployments_url":"https://api.github.com/repos/pulp/pulp/deployments","created_at":"2012-08-06T13:49:20Z","updated_at":"2016-07-23T19:14:08Z","pushed_at":"2016-07-22T21:58:06Z","git_url":"git://github.com/pulp/pulp.git","ssh_url":"git@github.com:pulp/pulp.git","clone_url":"https://github.com/pulp/pulp.git","svn_url":"https://github.com/pulp/pulp","homepage":"","size":103847,"stargazers_count":274,"watchers_count":274,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":112,"mirror_url":null,"open_issues_count":18,"forks":112,"open_issues":18,"watchers":274,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pulp/pulp/pulls/2624"},"html":{"href":"https://github.com/pulp/pulp/pull/2624"},"issue":{"href":"https://api.github.com/repos/pulp/pulp/issues/2624"},"comments":{"href":"https://api.github.com/repos/pulp/pulp/issues/2624/comments"},"review_comments":{"href":"https://api.github.com/repos/pulp/pulp/pulls/2624/comments"},"review_comment":{"href":"https://api.github.com/repos/pulp/pulp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pulp/pulp/pulls/2624/commits"},"statuses":{"href":"https://api.github.com/repos/pulp/pulp/statuses/480b75b8d60785bfb80548374749de7ce8a08398"}}}}
{"actor":{"display_login":"dkliban"}}