{"action":"created","comment":{"url":"https://api.github.com/repos/checkmate/chessboard/pulls/comments/30490578","id":30490578,"diff_hunk":"@@ -0,0 +1,186 @@\n+# Copyright 2015 Rackspace US, Inc.\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+#    http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+\"\"\"Classes and utilities for modeling and handling application topology.\"\"\"\n+\n+from collections import OrderedDict\n+\n+\n+class TopologyError(Exception):\n+\n+    \"\"\"Basic exception type for errors related to :class:`Topology`.\"\"\"\n+\n+\n+class Topology(object):\n+\n+    \"\"\"Construct and validate the relations between application services.\n+\n+    The main thing this class does right now is read parsed and validated\n+    Checkmatefile contents (see :meth:`from_checkmatefile`), analyze the\n+    relations defined for each service, create a simple mapping for those\n+    connections, and check that the relations are valid.\n+    \"\"\"\n+\n+    def __init__(self, services):\n+        \"\"\"Create a new Topology from a collection of :class:`Service` objects.\n+\n+        :param dict services:\n+            Dictionary of :class:`Service` objects, keyed by name.\n+        \"\"\"\n+        self.services = services\n+        self.relations = OrderedDict()\n+        self._connect_services()\n+\n+    def _connect_services(self):\n+        \"\"\"Wire up services, per the defined relations.\n+\n+        This performs some semantic validation checks on the application\n+        topology; specifically, we check to make sure relations refer to valid\n+        services. If a service is connected to another service which doesn't\n+        exist, an error should be raised. Likewise, if a remote service exists\n+        but does not expose an interface matching the interface of the\n+        relation, an error should be raised.\n+\n+        :raises:\n+            :exception:`TopologyError` on invalid relations.\n+        \"\"\"\n+        for service_name, service in self.services.items():\n+            if service.relations:\n+\n+                connections = []\n+                for conn in service.relations:\n+                    remote_service = conn['service']\n+                    remote_interface = conn['interface']\n+                    if remote_service not in self.services:\n+                        # The remote service we want to connect to doesn't\n+                        # exist.\n+                        raise TopologyError(\n+                            \"Service '%(sn)s' defines a relation to an unknown\"\n+                            \" remote service '%(rs)s'.\"\n+                            % dict(sn=service_name, rs=remote_service)\n+                        )\n+                    else:\n+                        # The remote service exists.\n+                        # Does the remote service operate on the interface we\n+                        # expect?\n+                        component_interface = (\n+                            self.services[remote_service].component.interface\n+                        )\n+                        if remote_interface == component_interface:","path":"chessboard/topology.py","position":null,"original_position":80,"commit_id":"88808995e1ea351a980710e99aa3dca6f2334980","original_commit_id":"a1af6500f91082158207e428e85988ad9a0b64e6","user":{"login":"larsbutler","id":464394,"avatar_url":"https://avatars.githubusercontent.com/u/464394?v=3","gravatar_id":"","url":"https://api.github.com/users/larsbutler","html_url":"https://github.com/larsbutler","followers_url":"https://api.github.com/users/larsbutler/followers","following_url":"https://api.github.com/users/larsbutler/following{/other_user}","gists_url":"https://api.github.com/users/larsbutler/gists{/gist_id}","starred_url":"https://api.github.com/users/larsbutler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsbutler/subscriptions","organizations_url":"https://api.github.com/users/larsbutler/orgs","repos_url":"https://api.github.com/users/larsbutler/repos","events_url":"https://api.github.com/users/larsbutler/events{/privacy}","received_events_url":"https://api.github.com/users/larsbutler/received_events","type":"User","site_admin":false},"body":"Okay, I'll remove this check.","created_at":"2015-05-18T08:55:51Z","updated_at":"2015-05-18T08:55:51Z","html_url":"https://github.com/checkmate/chessboard/pull/21#discussion_r30490578","pull_request_url":"https://api.github.com/repos/checkmate/chessboard/pulls/21","_links":{"self":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/comments/30490578"},"html":{"href":"https://github.com/checkmate/chessboard/pull/21#discussion_r30490578"},"pull_request":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/21"}}},"pull_request":{"url":"https://api.github.com/repos/checkmate/chessboard/pulls/21","id":35012801,"html_url":"https://github.com/checkmate/chessboard/pull/21","diff_url":"https://github.com/checkmate/chessboard/pull/21.diff","patch_url":"https://github.com/checkmate/chessboard/pull/21.patch","issue_url":"https://api.github.com/repos/checkmate/chessboard/issues/21","number":21,"state":"open","locked":false,"title":"Generate Topology from Checkmatefile","user":{"login":"larsbutler","id":464394,"avatar_url":"https://avatars.githubusercontent.com/u/464394?v=3","gravatar_id":"","url":"https://api.github.com/users/larsbutler","html_url":"https://github.com/larsbutler","followers_url":"https://api.github.com/users/larsbutler/followers","following_url":"https://api.github.com/users/larsbutler/following{/other_user}","gists_url":"https://api.github.com/users/larsbutler/gists{/gist_id}","starred_url":"https://api.github.com/users/larsbutler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsbutler/subscriptions","organizations_url":"https://api.github.com/users/larsbutler/orgs","repos_url":"https://api.github.com/users/larsbutler/repos","events_url":"https://api.github.com/users/larsbutler/events{/privacy}","received_events_url":"https://api.github.com/users/larsbutler/received_events","type":"User","site_admin":false},"body":"https://github.com/checkmate/chessboard/pull/20 should merge first for a clean diff. Only the last two commits a049bf4 and b5cc3cf are relevant.\r\n\r\nThis is a first draft of this functionality, which partially addresses https://github.com/checkmate/chessboard/issues/18.","created_at":"2015-05-08T14:19:05Z","updated_at":"2015-05-18T08:55:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cebe80faf2c835db54c4fc235c6f445d262c7adc","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/checkmate/chessboard/pulls/21/commits","review_comments_url":"https://api.github.com/repos/checkmate/chessboard/pulls/21/comments","review_comment_url":"https://api.github.com/repos/checkmate/chessboard/pulls/comments{/number}","comments_url":"https://api.github.com/repos/checkmate/chessboard/issues/21/comments","statuses_url":"https://api.github.com/repos/checkmate/chessboard/statuses/88808995e1ea351a980710e99aa3dca6f2334980","head":{"label":"larsbutler:generate-topology","ref":"generate-topology","sha":"88808995e1ea351a980710e99aa3dca6f2334980","user":{"login":"larsbutler","id":464394,"avatar_url":"https://avatars.githubusercontent.com/u/464394?v=3","gravatar_id":"","url":"https://api.github.com/users/larsbutler","html_url":"https://github.com/larsbutler","followers_url":"https://api.github.com/users/larsbutler/followers","following_url":"https://api.github.com/users/larsbutler/following{/other_user}","gists_url":"https://api.github.com/users/larsbutler/gists{/gist_id}","starred_url":"https://api.github.com/users/larsbutler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsbutler/subscriptions","organizations_url":"https://api.github.com/users/larsbutler/orgs","repos_url":"https://api.github.com/users/larsbutler/repos","events_url":"https://api.github.com/users/larsbutler/events{/privacy}","received_events_url":"https://api.github.com/users/larsbutler/received_events","type":"User","site_admin":false},"repo":{"id":34248979,"name":"chessboard","full_name":"larsbutler/chessboard","owner":{"login":"larsbutler","id":464394,"avatar_url":"https://avatars.githubusercontent.com/u/464394?v=3","gravatar_id":"","url":"https://api.github.com/users/larsbutler","html_url":"https://github.com/larsbutler","followers_url":"https://api.github.com/users/larsbutler/followers","following_url":"https://api.github.com/users/larsbutler/following{/other_user}","gists_url":"https://api.github.com/users/larsbutler/gists{/gist_id}","starred_url":"https://api.github.com/users/larsbutler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsbutler/subscriptions","organizations_url":"https://api.github.com/users/larsbutler/orgs","repos_url":"https://api.github.com/users/larsbutler/repos","events_url":"https://api.github.com/users/larsbutler/events{/privacy}","received_events_url":"https://api.github.com/users/larsbutler/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/larsbutler/chessboard","description":"","fork":true,"url":"https://api.github.com/repos/larsbutler/chessboard","forks_url":"https://api.github.com/repos/larsbutler/chessboard/forks","keys_url":"https://api.github.com/repos/larsbutler/chessboard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/larsbutler/chessboard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/larsbutler/chessboard/teams","hooks_url":"https://api.github.com/repos/larsbutler/chessboard/hooks","issue_events_url":"https://api.github.com/repos/larsbutler/chessboard/issues/events{/number}","events_url":"https://api.github.com/repos/larsbutler/chessboard/events","assignees_url":"https://api.github.com/repos/larsbutler/chessboard/assignees{/user}","branches_url":"https://api.github.com/repos/larsbutler/chessboard/branches{/branch}","tags_url":"https://api.github.com/repos/larsbutler/chessboard/tags","blobs_url":"https://api.github.com/repos/larsbutler/chessboard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/larsbutler/chessboard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/larsbutler/chessboard/git/refs{/sha}","trees_url":"https://api.github.com/repos/larsbutler/chessboard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/larsbutler/chessboard/statuses/{sha}","languages_url":"https://api.github.com/repos/larsbutler/chessboard/languages","stargazers_url":"https://api.github.com/repos/larsbutler/chessboard/stargazers","contributors_url":"https://api.github.com/repos/larsbutler/chessboard/contributors","subscribers_url":"https://api.github.com/repos/larsbutler/chessboard/subscribers","subscription_url":"https://api.github.com/repos/larsbutler/chessboard/subscription","commits_url":"https://api.github.com/repos/larsbutler/chessboard/commits{/sha}","git_commits_url":"https://api.github.com/repos/larsbutler/chessboard/git/commits{/sha}","comments_url":"https://api.github.com/repos/larsbutler/chessboard/comments{/number}","issue_comment_url":"https://api.github.com/repos/larsbutler/chessboard/issues/comments{/number}","contents_url":"https://api.github.com/repos/larsbutler/chessboard/contents/{+path}","compare_url":"https://api.github.com/repos/larsbutler/chessboard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/larsbutler/chessboard/merges","archive_url":"https://api.github.com/repos/larsbutler/chessboard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/larsbutler/chessboard/downloads","issues_url":"https://api.github.com/repos/larsbutler/chessboard/issues{/number}","pulls_url":"https://api.github.com/repos/larsbutler/chessboard/pulls{/number}","milestones_url":"https://api.github.com/repos/larsbutler/chessboard/milestones{/number}","notifications_url":"https://api.github.com/repos/larsbutler/chessboard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/larsbutler/chessboard/labels{/name}","releases_url":"https://api.github.com/repos/larsbutler/chessboard/releases{/id}","created_at":"2015-04-20T08:43:47Z","updated_at":"2015-04-24T13:28:51Z","pushed_at":"2015-05-18T08:55:40Z","git_url":"git://github.com/larsbutler/chessboard.git","ssh_url":"git@github.com:larsbutler/chessboard.git","clone_url":"https://github.com/larsbutler/chessboard.git","svn_url":"https://github.com/larsbutler/chessboard","homepage":null,"size":281,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"checkmate:master","ref":"master","sha":"adb7bbc9337ade830c40af7497d58b586fab4b87","user":{"login":"checkmate","id":2694892,"avatar_url":"https://avatars.githubusercontent.com/u/2694892?v=3","gravatar_id":"","url":"https://api.github.com/users/checkmate","html_url":"https://github.com/checkmate","followers_url":"https://api.github.com/users/checkmate/followers","following_url":"https://api.github.com/users/checkmate/following{/other_user}","gists_url":"https://api.github.com/users/checkmate/gists{/gist_id}","starred_url":"https://api.github.com/users/checkmate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/checkmate/subscriptions","organizations_url":"https://api.github.com/users/checkmate/orgs","repos_url":"https://api.github.com/users/checkmate/repos","events_url":"https://api.github.com/users/checkmate/events{/privacy}","received_events_url":"https://api.github.com/users/checkmate/received_events","type":"Organization","site_admin":false},"repo":{"id":34247900,"name":"chessboard","full_name":"checkmate/chessboard","owner":{"login":"checkmate","id":2694892,"avatar_url":"https://avatars.githubusercontent.com/u/2694892?v=3","gravatar_id":"","url":"https://api.github.com/users/checkmate","html_url":"https://github.com/checkmate","followers_url":"https://api.github.com/users/checkmate/followers","following_url":"https://api.github.com/users/checkmate/following{/other_user}","gists_url":"https://api.github.com/users/checkmate/gists{/gist_id}","starred_url":"https://api.github.com/users/checkmate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/checkmate/subscriptions","organizations_url":"https://api.github.com/users/checkmate/orgs","repos_url":"https://api.github.com/users/checkmate/repos","events_url":"https://api.github.com/users/checkmate/events{/privacy}","received_events_url":"https://api.github.com/users/checkmate/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/checkmate/chessboard","description":"","fork":false,"url":"https://api.github.com/repos/checkmate/chessboard","forks_url":"https://api.github.com/repos/checkmate/chessboard/forks","keys_url":"https://api.github.com/repos/checkmate/chessboard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/checkmate/chessboard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/checkmate/chessboard/teams","hooks_url":"https://api.github.com/repos/checkmate/chessboard/hooks","issue_events_url":"https://api.github.com/repos/checkmate/chessboard/issues/events{/number}","events_url":"https://api.github.com/repos/checkmate/chessboard/events","assignees_url":"https://api.github.com/repos/checkmate/chessboard/assignees{/user}","branches_url":"https://api.github.com/repos/checkmate/chessboard/branches{/branch}","tags_url":"https://api.github.com/repos/checkmate/chessboard/tags","blobs_url":"https://api.github.com/repos/checkmate/chessboard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/checkmate/chessboard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/checkmate/chessboard/git/refs{/sha}","trees_url":"https://api.github.com/repos/checkmate/chessboard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/checkmate/chessboard/statuses/{sha}","languages_url":"https://api.github.com/repos/checkmate/chessboard/languages","stargazers_url":"https://api.github.com/repos/checkmate/chessboard/stargazers","contributors_url":"https://api.github.com/repos/checkmate/chessboard/contributors","subscribers_url":"https://api.github.com/repos/checkmate/chessboard/subscribers","subscription_url":"https://api.github.com/repos/checkmate/chessboard/subscription","commits_url":"https://api.github.com/repos/checkmate/chessboard/commits{/sha}","git_commits_url":"https://api.github.com/repos/checkmate/chessboard/git/commits{/sha}","comments_url":"https://api.github.com/repos/checkmate/chessboard/comments{/number}","issue_comment_url":"https://api.github.com/repos/checkmate/chessboard/issues/comments{/number}","contents_url":"https://api.github.com/repos/checkmate/chessboard/contents/{+path}","compare_url":"https://api.github.com/repos/checkmate/chessboard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/checkmate/chessboard/merges","archive_url":"https://api.github.com/repos/checkmate/chessboard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/checkmate/chessboard/downloads","issues_url":"https://api.github.com/repos/checkmate/chessboard/issues{/number}","pulls_url":"https://api.github.com/repos/checkmate/chessboard/pulls{/number}","milestones_url":"https://api.github.com/repos/checkmate/chessboard/milestones{/number}","notifications_url":"https://api.github.com/repos/checkmate/chessboard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/checkmate/chessboard/labels{/name}","releases_url":"https://api.github.com/repos/checkmate/chessboard/releases{/id}","created_at":"2015-04-20T08:22:06Z","updated_at":"2015-05-05T09:38:53Z","pushed_at":"2015-05-18T08:55:41Z","git_url":"git://github.com/checkmate/chessboard.git","ssh_url":"git@github.com:checkmate/chessboard.git","clone_url":"https://github.com/checkmate/chessboard.git","svn_url":"https://github.com/checkmate/chessboard","homepage":null,"size":561,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":14,"forks":2,"open_issues":14,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/21"},"html":{"href":"https://github.com/checkmate/chessboard/pull/21"},"issue":{"href":"https://api.github.com/repos/checkmate/chessboard/issues/21"},"comments":{"href":"https://api.github.com/repos/checkmate/chessboard/issues/21/comments"},"review_comments":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/21/comments"},"review_comment":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/checkmate/chessboard/pulls/21/commits"},"statuses":{"href":"https://api.github.com/repos/checkmate/chessboard/statuses/88808995e1ea351a980710e99aa3dca6f2334980"}}}}