{"action":"created","comment":{"url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/comments/157675131","pull_request_review_id":84355339,"id":157675131,"diff_hunk":"@@ -435,19 +436,96 @@ def copy_file_to_tmp(host, file):\n \n \n def validate_xml(filename):\n-    # FIXME: Check mandatory fields.\n     correct = True\n-    with open(filename, 'rb') as file:\n-        xmlcontents = file.read()\n     try:\n-        ElementTree.fromstring(xmlcontents)\n+        xmltree = ElementTree.parse(filename);\n+        root = xmltree.getroot()\n+        for runtime in root.findall('runtime'):\n+\n+            # Only one 'id' subelement is allowed.\n+            pattern = re.compile(r'^[a-zA-Z0-9][a-zA-Z0-9_.-]*$')\n+            num = len(runtime.findall('id'))\n+            if num < 1:\n+                logger.error(\"Lack of 'id' subelement in a runtime element.\")\n+                raise Exception(\"Validation failed\")\n+            if num > 1:\n+                logger.error(\"Found %d (1 is legal) 'id' subelements in a runtime element. The first one 'id': %s\", num, runtime.find('id').text)\n+                raise Exception(\"Validation failed\")\n+\n+            runtime_id = runtime.find('id').text\n+            if  not pattern.match(runtime_id):\n+                logger.error(\"'id' name with wrong format: %s\", runtime_id)\n+                raise Exception(\"Validation failed\")\n+\n+            # Only one 'image' subelement is allowed.\n+            num = len(runtime.findall('image'))\n+            if num < 1:\n+                logger.error(\"Lack of 'image' subelement in a runtime element in runtime %s.\", runtime_id)\n+                raise Exception(\"Validation failed\")\n+            if num > 1:\n+                logger.error(\"Found %d (1 is legal) 'image' subelements in a runtime %s. The first one 'image': %s\", num, runtime_id, runtime.find('image').text)\n+                raise Exception(\"Validation failed\")\n+            # FIXME: Need to check the naming convention?\n+\n+            # Only one 'command' subelement is allowed.\n+            num = len(runtime.findall('command'))\n+            if num < 1:\n+                logger.error(\"Lack of 'command' subelement in a runtime element in runtime %s.\", runtime_id)\n+                raise Exception(\"Validation failed\")\n+            if num > 1:\n+                logger.error(\"Found %d (1 is legal) 'command' subelements in runtime %s. The first one 'command': %s\", num, runtime_id, runtime.find('command').text)\n+                raise Exception(\"Validation failed\")\n+\n+            # Shared\n+            container_pathlist = []\n+            for share_folder in runtime.findall('shared_directory'):\n+\n+                if 'access' in share_folder.attrib and share_folder.attrib['access'] != 'ro' and share_folder.attrib['access'] != 'rw':\n+                    logger.error(\"access should be 'ro' or 'rw' in shared_directory in runtime %s, but now: %s\", runtime_id, share_folder.attrib['access'])\n+                    raise Exception(\"Validation failed\")\n+\n+                if  share_folder.attrib.keys() != ['access', 'host', 'container']:\n+                    logger.error(\"Unknown or missing attributes (need and only need 'access', 'host' and 'container') in shared_directory in runtime %s\", runtime_id)\n+                    logger.error(\"Current: %s\", share_folder.attrib.keys())\n+                    raise Exception(\"Validation failed\")\n+                container_pathlist.append(share_folder.attrib['container'])\n+","path":"management/bin/plcontainer","position":69,"original_position":69,"commit_id":"dba8cebd4e57e0d5e8a40f431ab806d2e10a1880","original_commit_id":"dba8cebd4e57e0d5e8a40f431ab806d2e10a1880","user":{"login":"paul-guo-","id":7485836,"avatar_url":"https://avatars3.githubusercontent.com/u/7485836?v=4","gravatar_id":"","url":"https://api.github.com/users/paul-guo-","html_url":"https://github.com/paul-guo-","followers_url":"https://api.github.com/users/paul-guo-/followers","following_url":"https://api.github.com/users/paul-guo-/following{/other_user}","gists_url":"https://api.github.com/users/paul-guo-/gists{/gist_id}","starred_url":"https://api.github.com/users/paul-guo-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paul-guo-/subscriptions","organizations_url":"https://api.github.com/users/paul-guo-/orgs","repos_url":"https://api.github.com/users/paul-guo-/repos","events_url":"https://api.github.com/users/paul-guo-/events{/privacy}","received_events_url":"https://api.github.com/users/paul-guo-/received_events","type":"User","site_admin":false},"body":"dup host paths are fine.","created_at":"2017-12-19T06:50:08Z","updated_at":"2017-12-19T06:50:08Z","html_url":"https://github.com/greenplum-db/plcontainer/pull/236#discussion_r157675131","pull_request_url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/comments/157675131"},"html":{"href":"https://github.com/greenplum-db/plcontainer/pull/236#discussion_r157675131"},"pull_request":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236"}},"in_reply_to_id":157672642},"pull_request":{"url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236","id":159084215,"html_url":"https://github.com/greenplum-db/plcontainer/pull/236","diff_url":"https://github.com/greenplum-db/plcontainer/pull/236.diff","patch_url":"https://github.com/greenplum-db/plcontainer/pull/236.patch","issue_url":"https://api.github.com/repos/greenplum-db/plcontainer/issues/236","number":236,"state":"open","locked":false,"title":"xml file validation code in plcontainer utility should be more aggressive","user":{"login":"paul-guo-","id":7485836,"avatar_url":"https://avatars3.githubusercontent.com/u/7485836?v=4","gravatar_id":"","url":"https://api.github.com/users/paul-guo-","html_url":"https://github.com/paul-guo-","followers_url":"https://api.github.com/users/paul-guo-/followers","following_url":"https://api.github.com/users/paul-guo-/following{/other_user}","gists_url":"https://api.github.com/users/paul-guo-/gists{/gist_id}","starred_url":"https://api.github.com/users/paul-guo-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paul-guo-/subscriptions","organizations_url":"https://api.github.com/users/paul-guo-/orgs","repos_url":"https://api.github.com/users/paul-guo-/repos","events_url":"https://api.github.com/users/paul-guo-/events{/privacy}","received_events_url":"https://api.github.com/users/paul-guo-/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-12-19T05:53:14Z","updated_at":"2017-12-19T06:50:08Z","closed_at":null,"merged_at":null,"merge_commit_sha":"599a6bf4d94a952d4ddcff6c4d5046356a55c68a","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236/commits","review_comments_url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236/comments","review_comment_url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/comments{/number}","comments_url":"https://api.github.com/repos/greenplum-db/plcontainer/issues/236/comments","statuses_url":"https://api.github.com/repos/greenplum-db/plcontainer/statuses/dba8cebd4e57e0d5e8a40f431ab806d2e10a1880","head":{"label":"paul-guo-:misc3","ref":"misc3","sha":"dba8cebd4e57e0d5e8a40f431ab806d2e10a1880","user":{"login":"paul-guo-","id":7485836,"avatar_url":"https://avatars3.githubusercontent.com/u/7485836?v=4","gravatar_id":"","url":"https://api.github.com/users/paul-guo-","html_url":"https://github.com/paul-guo-","followers_url":"https://api.github.com/users/paul-guo-/followers","following_url":"https://api.github.com/users/paul-guo-/following{/other_user}","gists_url":"https://api.github.com/users/paul-guo-/gists{/gist_id}","starred_url":"https://api.github.com/users/paul-guo-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paul-guo-/subscriptions","organizations_url":"https://api.github.com/users/paul-guo-/orgs","repos_url":"https://api.github.com/users/paul-guo-/repos","events_url":"https://api.github.com/users/paul-guo-/events{/privacy}","received_events_url":"https://api.github.com/users/paul-guo-/received_events","type":"User","site_admin":false},"repo":{"id":93355169,"name":"plcontainer","full_name":"paul-guo-/plcontainer","owner":{"login":"paul-guo-","id":7485836,"avatar_url":"https://avatars3.githubusercontent.com/u/7485836?v=4","gravatar_id":"","url":"https://api.github.com/users/paul-guo-","html_url":"https://github.com/paul-guo-","followers_url":"https://api.github.com/users/paul-guo-/followers","following_url":"https://api.github.com/users/paul-guo-/following{/other_user}","gists_url":"https://api.github.com/users/paul-guo-/gists{/gist_id}","starred_url":"https://api.github.com/users/paul-guo-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paul-guo-/subscriptions","organizations_url":"https://api.github.com/users/paul-guo-/orgs","repos_url":"https://api.github.com/users/paul-guo-/repos","events_url":"https://api.github.com/users/paul-guo-/events{/privacy}","received_events_url":"https://api.github.com/users/paul-guo-/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/paul-guo-/plcontainer","description":"PL/Container - GPDB execution sandboxing for Python and R","fork":true,"url":"https://api.github.com/repos/paul-guo-/plcontainer","forks_url":"https://api.github.com/repos/paul-guo-/plcontainer/forks","keys_url":"https://api.github.com/repos/paul-guo-/plcontainer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/paul-guo-/plcontainer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/paul-guo-/plcontainer/teams","hooks_url":"https://api.github.com/repos/paul-guo-/plcontainer/hooks","issue_events_url":"https://api.github.com/repos/paul-guo-/plcontainer/issues/events{/number}","events_url":"https://api.github.com/repos/paul-guo-/plcontainer/events","assignees_url":"https://api.github.com/repos/paul-guo-/plcontainer/assignees{/user}","branches_url":"https://api.github.com/repos/paul-guo-/plcontainer/branches{/branch}","tags_url":"https://api.github.com/repos/paul-guo-/plcontainer/tags","blobs_url":"https://api.github.com/repos/paul-guo-/plcontainer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/paul-guo-/plcontainer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/paul-guo-/plcontainer/git/refs{/sha}","trees_url":"https://api.github.com/repos/paul-guo-/plcontainer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/paul-guo-/plcontainer/statuses/{sha}","languages_url":"https://api.github.com/repos/paul-guo-/plcontainer/languages","stargazers_url":"https://api.github.com/repos/paul-guo-/plcontainer/stargazers","contributors_url":"https://api.github.com/repos/paul-guo-/plcontainer/contributors","subscribers_url":"https://api.github.com/repos/paul-guo-/plcontainer/subscribers","subscription_url":"https://api.github.com/repos/paul-guo-/plcontainer/subscription","commits_url":"https://api.github.com/repos/paul-guo-/plcontainer/commits{/sha}","git_commits_url":"https://api.github.com/repos/paul-guo-/plcontainer/git/commits{/sha}","comments_url":"https://api.github.com/repos/paul-guo-/plcontainer/comments{/number}","issue_comment_url":"https://api.github.com/repos/paul-guo-/plcontainer/issues/comments{/number}","contents_url":"https://api.github.com/repos/paul-guo-/plcontainer/contents/{+path}","compare_url":"https://api.github.com/repos/paul-guo-/plcontainer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/paul-guo-/plcontainer/merges","archive_url":"https://api.github.com/repos/paul-guo-/plcontainer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/paul-guo-/plcontainer/downloads","issues_url":"https://api.github.com/repos/paul-guo-/plcontainer/issues{/number}","pulls_url":"https://api.github.com/repos/paul-guo-/plcontainer/pulls{/number}","milestones_url":"https://api.github.com/repos/paul-guo-/plcontainer/milestones{/number}","notifications_url":"https://api.github.com/repos/paul-guo-/plcontainer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/paul-guo-/plcontainer/labels{/name}","releases_url":"https://api.github.com/repos/paul-guo-/plcontainer/releases{/id}","deployments_url":"https://api.github.com/repos/paul-guo-/plcontainer/deployments","created_at":"2017-06-05T02:02:38Z","updated_at":"2017-06-05T02:02:41Z","pushed_at":"2017-12-19T05:53:05Z","git_url":"git://github.com/paul-guo-/plcontainer.git","ssh_url":"git@github.com:paul-guo-/plcontainer.git","clone_url":"https://github.com/paul-guo-/plcontainer.git","svn_url":"https://github.com/paul-guo-/plcontainer","homepage":"","size":114834,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"greenplum-db:master","ref":"master","sha":"ada1f9b3c4245089b548eacb0005378ea07b261e","user":{"login":"greenplum-db","id":14097842,"avatar_url":"https://avatars2.githubusercontent.com/u/14097842?v=4","gravatar_id":"","url":"https://api.github.com/users/greenplum-db","html_url":"https://github.com/greenplum-db","followers_url":"https://api.github.com/users/greenplum-db/followers","following_url":"https://api.github.com/users/greenplum-db/following{/other_user}","gists_url":"https://api.github.com/users/greenplum-db/gists{/gist_id}","starred_url":"https://api.github.com/users/greenplum-db/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/greenplum-db/subscriptions","organizations_url":"https://api.github.com/users/greenplum-db/orgs","repos_url":"https://api.github.com/users/greenplum-db/repos","events_url":"https://api.github.com/users/greenplum-db/events{/privacy}","received_events_url":"https://api.github.com/users/greenplum-db/received_events","type":"Organization","site_admin":false},"repo":{"id":51456908,"name":"plcontainer","full_name":"greenplum-db/plcontainer","owner":{"login":"greenplum-db","id":14097842,"avatar_url":"https://avatars2.githubusercontent.com/u/14097842?v=4","gravatar_id":"","url":"https://api.github.com/users/greenplum-db","html_url":"https://github.com/greenplum-db","followers_url":"https://api.github.com/users/greenplum-db/followers","following_url":"https://api.github.com/users/greenplum-db/following{/other_user}","gists_url":"https://api.github.com/users/greenplum-db/gists{/gist_id}","starred_url":"https://api.github.com/users/greenplum-db/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/greenplum-db/subscriptions","organizations_url":"https://api.github.com/users/greenplum-db/orgs","repos_url":"https://api.github.com/users/greenplum-db/repos","events_url":"https://api.github.com/users/greenplum-db/events{/privacy}","received_events_url":"https://api.github.com/users/greenplum-db/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/greenplum-db/plcontainer","description":"PL/Container - GPDB execution sandboxing for Python and R","fork":false,"url":"https://api.github.com/repos/greenplum-db/plcontainer","forks_url":"https://api.github.com/repos/greenplum-db/plcontainer/forks","keys_url":"https://api.github.com/repos/greenplum-db/plcontainer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/greenplum-db/plcontainer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/greenplum-db/plcontainer/teams","hooks_url":"https://api.github.com/repos/greenplum-db/plcontainer/hooks","issue_events_url":"https://api.github.com/repos/greenplum-db/plcontainer/issues/events{/number}","events_url":"https://api.github.com/repos/greenplum-db/plcontainer/events","assignees_url":"https://api.github.com/repos/greenplum-db/plcontainer/assignees{/user}","branches_url":"https://api.github.com/repos/greenplum-db/plcontainer/branches{/branch}","tags_url":"https://api.github.com/repos/greenplum-db/plcontainer/tags","blobs_url":"https://api.github.com/repos/greenplum-db/plcontainer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/greenplum-db/plcontainer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/greenplum-db/plcontainer/git/refs{/sha}","trees_url":"https://api.github.com/repos/greenplum-db/plcontainer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/greenplum-db/plcontainer/statuses/{sha}","languages_url":"https://api.github.com/repos/greenplum-db/plcontainer/languages","stargazers_url":"https://api.github.com/repos/greenplum-db/plcontainer/stargazers","contributors_url":"https://api.github.com/repos/greenplum-db/plcontainer/contributors","subscribers_url":"https://api.github.com/repos/greenplum-db/plcontainer/subscribers","subscription_url":"https://api.github.com/repos/greenplum-db/plcontainer/subscription","commits_url":"https://api.github.com/repos/greenplum-db/plcontainer/commits{/sha}","git_commits_url":"https://api.github.com/repos/greenplum-db/plcontainer/git/commits{/sha}","comments_url":"https://api.github.com/repos/greenplum-db/plcontainer/comments{/number}","issue_comment_url":"https://api.github.com/repos/greenplum-db/plcontainer/issues/comments{/number}","contents_url":"https://api.github.com/repos/greenplum-db/plcontainer/contents/{+path}","compare_url":"https://api.github.com/repos/greenplum-db/plcontainer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/greenplum-db/plcontainer/merges","archive_url":"https://api.github.com/repos/greenplum-db/plcontainer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/greenplum-db/plcontainer/downloads","issues_url":"https://api.github.com/repos/greenplum-db/plcontainer/issues{/number}","pulls_url":"https://api.github.com/repos/greenplum-db/plcontainer/pulls{/number}","milestones_url":"https://api.github.com/repos/greenplum-db/plcontainer/milestones{/number}","notifications_url":"https://api.github.com/repos/greenplum-db/plcontainer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/greenplum-db/plcontainer/labels{/name}","releases_url":"https://api.github.com/repos/greenplum-db/plcontainer/releases{/id}","deployments_url":"https://api.github.com/repos/greenplum-db/plcontainer/deployments","created_at":"2016-02-10T17:14:28Z","updated_at":"2017-11-24T13:29:27Z","pushed_at":"2017-12-19T05:53:14Z","git_url":"git://github.com/greenplum-db/plcontainer.git","ssh_url":"git@github.com:greenplum-db/plcontainer.git","clone_url":"https://github.com/greenplum-db/plcontainer.git","svn_url":"https://github.com/greenplum-db/plcontainer","homepage":"","size":114743,"stargazers_count":14,"watchers_count":14,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"archived":false,"open_issues_count":18,"license":null,"forks":10,"open_issues":18,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236"},"html":{"href":"https://github.com/greenplum-db/plcontainer/pull/236"},"issue":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/issues/236"},"comments":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/issues/236/comments"},"review_comments":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236/comments"},"review_comment":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/pulls/236/commits"},"statuses":{"href":"https://api.github.com/repos/greenplum-db/plcontainer/statuses/dba8cebd4e57e0d5e8a40f431ab806d2e10a1880"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"paul-guo-"}}