{"action":"created","comment":{"url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments/50308457","id":50308457,"diff_hunk":"@@ -86,23 +101,78 @@\n    \"store report\" (version-range 3 6)\n    \"deactivate node\" (version-range 1 3)})\n \n-;; ## Command parsing\n+(defn- read-command-body\n+  [body]\n+  (if (= (class body) (class (byte-array 0)))\n+    (json/parse-string (String. body \"UTF-8\") true)\n+    (json/parse-string body true)))\n+\n+(defn- die-on-header-payload-mismatch\n+  [name in-header in-body]\n+  (when (and in-header in-body (not= in-header in-body))\n+    (throw+\n+     (fatality\n+      (Exception.\n+       (format \"%s mismatch between message properties and payload (%s != %s)\"\n+               name in-header in-body))))))\n+\n+(defn parse-new-command\n+  \"Parses a new-format queue command and returns it in the traditional\n+  format.\"\n+  [{:keys [headers body]}]\n+  ;; New-style messages must have all 5 headers, and the body must be\n+  ;; the bare command content (i.e. the payload).  So for\n+  ;; a \"deactivate node\" command,\n+  ;; a string like {\"certname\":\"test1\",\"producer_timestamp\":\"2015-01-01\"}.\n+  (let [{:keys [command version certname received id]} headers\n+        version (if-let [v (:version headers)] (Integer/parseInt v) nil)]\n+    (when-not (and command version certname received id)\n+      (throw+\n+       (fatality (Exception. (str \"Missing command message properties:\"\n+                                  (when-not command \" command\")\n+                                  (when-not version \" version\")\n+                                  (when-not certname \" certname\")\n+                                  (when-not received \" received\")\n+                                  (when-not id \" id\"))))))\n+    (let [message (read-command-body body)]\n+      (die-on-header-payload-mismatch \"certname\"\n+                                      certname\n+                                      (get-in message [\"payload\" \"certname\"]))\n+      (assert (not (:annotations message)))\n+      {:command command\n+       :version version\n+       :certname certname ;; Duplicated with respect to payload for now.\n+       :payload message\n+       :annotations (dissoc headers :command :version :certname)})))\n+\n+(defn- parse-queue-command\n+  [{:keys [headers body]}]\n+  ;; Queue messages must not have command, version, or certname headers,\n+  ;; and the body must be a JSON map like this:\n+  ;; {\"command\":\"deactivate node\",\"version\":3, \"payload\":{\"certname\":...}}\n+  (let [{:keys [command version certname]} headers]\n+    (when (or command version certname)","path":"src/puppetlabs/puppetdb/command.clj","position":77,"original_position":77,"commit_id":"0744cd49b7ef7bfc38ff737572fb2e3de8fc6bc6","original_commit_id":"0744cd49b7ef7bfc38ff737572fb2e3de8fc6bc6","user":{"login":"mullr","id":24409,"avatar_url":"https://avatars.githubusercontent.com/u/24409?v=3","gravatar_id":"","url":"https://api.github.com/users/mullr","html_url":"https://github.com/mullr","followers_url":"https://api.github.com/users/mullr/followers","following_url":"https://api.github.com/users/mullr/following{/other_user}","gists_url":"https://api.github.com/users/mullr/gists{/gist_id}","starred_url":"https://api.github.com/users/mullr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mullr/subscriptions","organizations_url":"https://api.github.com/users/mullr/orgs","repos_url":"https://api.github.com/users/mullr/repos","events_url":"https://api.github.com/users/mullr/events{/privacy}","received_events_url":"https://api.github.com/users/mullr/received_events","type":"User","site_admin":false},"body":"Similarly, a schema could do this job well. ","created_at":"2016-01-20T19:51:25Z","updated_at":"2016-01-20T19:51:25Z","html_url":"https://github.com/puppetlabs/puppetdb/pull/1812#discussion_r50308457","pull_request_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812","_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments/50308457"},"html":{"href":"https://github.com/puppetlabs/puppetdb/pull/1812#discussion_r50308457"},"pull_request":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812"}}},"pull_request":{"url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812","id":55916840,"html_url":"https://github.com/puppetlabs/puppetdb/pull/1812","diff_url":"https://github.com/puppetlabs/puppetdb/pull/1812.diff","patch_url":"https://github.com/puppetlabs/puppetdb/pull/1812.patch","issue_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1812","number":1812,"state":"open","locked":false,"title":"(PDB-2252) Try to avoid parsing a POSTed cmd","user":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"body":"Don't parse the incoming command body when it has command and version\r\nparameters (which should now be the common case).  Instead, validate the\r\nparameters, and pass the body directly to the queue, uninterpreted.\r\nOtherwise, warn if body has to be parsed into RAM.\r\n\r\nAttach the command, version, and if available, certname, to the queue\r\nmessage as JMS properties, extracting them from the body (after\r\nparsing), if they weren't available in the incoming request.\r\n\r\nAs before, reject incoming commands that don't have both command and\r\nversion when they have either.\r\n","created_at":"2016-01-13T16:03:33Z","updated_at":"2016-01-20T19:51:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a53974a1d7bf3e0b63d042e025a4a15fa6ff2653","assignee":null,"milestone":{"url":"https://api.github.com/repos/puppetlabs/puppetdb/milestones/11","html_url":"https://github.com/puppetlabs/puppetdb/milestones/4.0.0%20(master)","labels_url":"https://api.github.com/repos/puppetlabs/puppetdb/milestones/11/labels","id":1341713,"number":11,"title":"4.0.0 (master)","description":"","creator":{"login":"kbarber","id":80595,"avatar_url":"https://avatars.githubusercontent.com/u/80595?v=3","gravatar_id":"","url":"https://api.github.com/users/kbarber","html_url":"https://github.com/kbarber","followers_url":"https://api.github.com/users/kbarber/followers","following_url":"https://api.github.com/users/kbarber/following{/other_user}","gists_url":"https://api.github.com/users/kbarber/gists{/gist_id}","starred_url":"https://api.github.com/users/kbarber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kbarber/subscriptions","organizations_url":"https://api.github.com/users/kbarber/orgs","repos_url":"https://api.github.com/users/kbarber/repos","events_url":"https://api.github.com/users/kbarber/events{/privacy}","received_events_url":"https://api.github.com/users/kbarber/received_events","type":"User","site_admin":false},"open_issues":5,"closed_issues":95,"state":"open","created_at":"2015-10-07T01:07:44Z","updated_at":"2016-01-20T15:11:23Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812/commits","review_comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812/comments","review_comment_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1812/comments","statuses_url":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/0744cd49b7ef7bfc38ff737572fb2e3de8fc6bc6","head":{"label":"rbrw:ticket/master/pdb-2252-avoid-parsing-cmd-body","ref":"ticket/master/pdb-2252-avoid-parsing-cmd-body","sha":"0744cd49b7ef7bfc38ff737572fb2e3de8fc6bc6","user":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"repo":{"id":27739513,"name":"puppetdb","full_name":"rbrw/puppetdb","owner":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rbrw/puppetdb","description":"Centralized Puppet Storage","fork":true,"url":"https://api.github.com/repos/rbrw/puppetdb","forks_url":"https://api.github.com/repos/rbrw/puppetdb/forks","keys_url":"https://api.github.com/repos/rbrw/puppetdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rbrw/puppetdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rbrw/puppetdb/teams","hooks_url":"https://api.github.com/repos/rbrw/puppetdb/hooks","issue_events_url":"https://api.github.com/repos/rbrw/puppetdb/issues/events{/number}","events_url":"https://api.github.com/repos/rbrw/puppetdb/events","assignees_url":"https://api.github.com/repos/rbrw/puppetdb/assignees{/user}","branches_url":"https://api.github.com/repos/rbrw/puppetdb/branches{/branch}","tags_url":"https://api.github.com/repos/rbrw/puppetdb/tags","blobs_url":"https://api.github.com/repos/rbrw/puppetdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rbrw/puppetdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rbrw/puppetdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/rbrw/puppetdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rbrw/puppetdb/statuses/{sha}","languages_url":"https://api.github.com/repos/rbrw/puppetdb/languages","stargazers_url":"https://api.github.com/repos/rbrw/puppetdb/stargazers","contributors_url":"https://api.github.com/repos/rbrw/puppetdb/contributors","subscribers_url":"https://api.github.com/repos/rbrw/puppetdb/subscribers","subscription_url":"https://api.github.com/repos/rbrw/puppetdb/subscription","commits_url":"https://api.github.com/repos/rbrw/puppetdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/rbrw/puppetdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/rbrw/puppetdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/rbrw/puppetdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/rbrw/puppetdb/contents/{+path}","compare_url":"https://api.github.com/repos/rbrw/puppetdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rbrw/puppetdb/merges","archive_url":"https://api.github.com/repos/rbrw/puppetdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rbrw/puppetdb/downloads","issues_url":"https://api.github.com/repos/rbrw/puppetdb/issues{/number}","pulls_url":"https://api.github.com/repos/rbrw/puppetdb/pulls{/number}","milestones_url":"https://api.github.com/repos/rbrw/puppetdb/milestones{/number}","notifications_url":"https://api.github.com/repos/rbrw/puppetdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rbrw/puppetdb/labels{/name}","releases_url":"https://api.github.com/repos/rbrw/puppetdb/releases{/id}","created_at":"2014-12-08T23:03:46Z","updated_at":"2014-12-08T23:03:47Z","pushed_at":"2016-01-19T23:38:11Z","git_url":"git://github.com/rbrw/puppetdb.git","ssh_url":"git@github.com:rbrw/puppetdb.git","clone_url":"https://github.com/rbrw/puppetdb.git","svn_url":"https://github.com/rbrw/puppetdb","homepage":"http://docs.puppetlabs.com/puppetdb","size":15515,"stargazers_count":0,"watchers_count":0,"language":"Clojure","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":"puppetlabs:master","ref":"master","sha":"9fdc558e69e1d7f75b907883123ca796a6edb1c8","user":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"repo":{"id":2193032,"name":"puppetdb","full_name":"puppetlabs/puppetdb","owner":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/puppetlabs/puppetdb","description":"Centralized Puppet Storage","fork":false,"url":"https://api.github.com/repos/puppetlabs/puppetdb","forks_url":"https://api.github.com/repos/puppetlabs/puppetdb/forks","keys_url":"https://api.github.com/repos/puppetlabs/puppetdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/puppetlabs/puppetdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/puppetlabs/puppetdb/teams","hooks_url":"https://api.github.com/repos/puppetlabs/puppetdb/hooks","issue_events_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/events{/number}","events_url":"https://api.github.com/repos/puppetlabs/puppetdb/events","assignees_url":"https://api.github.com/repos/puppetlabs/puppetdb/assignees{/user}","branches_url":"https://api.github.com/repos/puppetlabs/puppetdb/branches{/branch}","tags_url":"https://api.github.com/repos/puppetlabs/puppetdb/tags","blobs_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/{sha}","languages_url":"https://api.github.com/repos/puppetlabs/puppetdb/languages","stargazers_url":"https://api.github.com/repos/puppetlabs/puppetdb/stargazers","contributors_url":"https://api.github.com/repos/puppetlabs/puppetdb/contributors","subscribers_url":"https://api.github.com/repos/puppetlabs/puppetdb/subscribers","subscription_url":"https://api.github.com/repos/puppetlabs/puppetdb/subscription","commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/puppetlabs/puppetdb/contents/{+path}","compare_url":"https://api.github.com/repos/puppetlabs/puppetdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/puppetlabs/puppetdb/merges","archive_url":"https://api.github.com/repos/puppetlabs/puppetdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/puppetlabs/puppetdb/downloads","issues_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues{/number}","pulls_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls{/number}","milestones_url":"https://api.github.com/repos/puppetlabs/puppetdb/milestones{/number}","notifications_url":"https://api.github.com/repos/puppetlabs/puppetdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/puppetlabs/puppetdb/labels{/name}","releases_url":"https://api.github.com/repos/puppetlabs/puppetdb/releases{/id}","created_at":"2011-08-11T18:54:46Z","updated_at":"2016-01-12T01:30:49Z","pushed_at":"2016-01-20T18:56:59Z","git_url":"git://github.com/puppetlabs/puppetdb.git","ssh_url":"git@github.com:puppetlabs/puppetdb.git","clone_url":"https://github.com/puppetlabs/puppetdb.git","svn_url":"https://github.com/puppetlabs/puppetdb","homepage":"http://docs.puppetlabs.com/puppetdb","size":18976,"stargazers_count":178,"watchers_count":178,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":143,"mirror_url":null,"open_issues_count":7,"forks":143,"open_issues":7,"watchers":178,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812"},"html":{"href":"https://github.com/puppetlabs/puppetdb/pull/1812"},"issue":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1812"},"comments":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1812/comments"},"review_comments":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812/comments"},"review_comment":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1812/commits"},"statuses":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/0744cd49b7ef7bfc38ff737572fb2e3de8fc6bc6"}}}}