{"action":"created","comment":{"url":"https://api.github.com/repos/convox/rack/pulls/comments/57652824","id":57652824,"diff_hunk":"@@ -0,0 +1,273 @@\n+# Convox Rack Development Guide\n+\n+Rack is open source with the goal of everyone to understand the platform, provide suggestions, and contribute improvements.\n+\n+This guide documents how to:\n+\n+* Set up a sandbox AWS Rack to develop and test infrastructure template changes\n+* Set up a laptop with a Docker VM to run, develop and test API changes locally\n+* Run the Rack unit test suite on a laptop\n+* Submit changes upstream\n+* Run an AWS integration test suite locally or on a CI server\n+* Release artifacts to enable `convox rack update`\n+\n+## Sponsorship and Mentoring\n+\n+Developing Rack will incur AWS costs. If this is an obstacle for you to contribute you can contact [support@convox.com](mailto:support@convox.com) to request sponsorship.\n+\n+Much of the technical design and implementation in Rack requires understanding of AWS, Docker, Golang, systems engineering and more. If you would like to better learn these systems to contribute, you can contact support@convox.com, join the [Public Slack](http://invite.convox.com/), or open up issues on [GitHub](http://github.com/convox/rack) to ask questions and/or request a mentor.\n+\n+## Sandbox AWS Rack Install\n+\n+Rack consumes numerous AWS and Docker APIs. The easiest way to develop Rack is with real AWS access keys interacting with real AWS resources like a Dynamo Table, ECS Cluster, and CloudFormation Stack.\n+\n+This is easy to bootstrap with the Rack project itself:\n+\n+```\n+$ convox install --stack-name dev\n+```\n+\n+You can also use any existing Rack with the caveat that running a laptop Rack against it could have side effects like terminating instances.\n+\n+## AWS Rack Ingress\n+\n+Parts of the API like `convox ps --stats` interact with the Docker daemon running on every AWS instance. To enable `convox ps --stats` to work from a laptop you will want to open up access to the instance Docker daemons:\n+\n+* Open the [Security Group Management Console](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#SecurityGroups)\n+* Select the Security Group with the Group Name like \"dev-SecurityGroup-4PNOYR5HUH83\" and the Description \"Instances\"\n+* Click the Inbound tab, then the Edit button, then the Add Rule button\n+* Keep Custom TCP Rule and TCP protocol\n+* Add \"2376\" for Port Range, and select \"My IP\" for Source\n+* Click the Save button\n+\n+Warning: Do not expose instance port 2376 to \"Anywhere\"! This will expose your Docker daemons to the whole Internet.\n+\n+## Rack Golang Project\n+\n+Rack is written in Golang. To setup a Go environment, see the excellent [Getting Started](https://golang.org/doc/install) docs. You can then clone and build the project with the `go get` tool:\n+\n+```\n+$ go get github.com/convox/rack/...\n+```\n+\n+After this, `which convox` should refer to `$GOPATH/bin/convox`.\n+\n+## Laptop Rack Environment\n+\n+The laptop Rack is running an API process that has AWS Access Keys, AWS resource names, and other various settings in its environment. You need to copy this to your laptop\n+\n+```\n+$ cd $GOPATH/src/github.com/convox/rack\n+\n+# Introspect the dev rack to find the PID of the API web process\n+\n+$ STACK_NAME=$(convox api get /system | jq -r .name)\n+$ WEB_PID=$(convox api get /apps/$STACK_NAME/processes | jq -r '.[] | select(.name == \"web\") | .id' | head -1)\n+\n+# Introspect the API web process to get its environment\n+\n+$ convox exec $WEB_PID env --app $STACK_NAME > .env\n+```\n+\n+Now you have a bunch of secrets that will let your laptop interact with AWS APIs:\n+\n+```\n+$ cat .env\n+CLIENT_ID=noah@convox.com\n+RACK=dev\n+SUBNETS=subnet-13de3139,subnet-b5578fc3,subnet-21c13379\n+AWS_ACCESS=AKIAIOSFODNN7EXAMPLE\n+AWS_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n+AWS_REGION=us-east-1\n+DYNAMO_RELEASES=dev-releases\n+CLUSTER=dev-Cluster-1E4XJ0PQWNAYS\n+PASSWORD=45e0f109-3f56-4b30-9b5a-b0939b8a4c25\n+...\n+```\n+\n+## Laptop Rack Docker VM\n+\n+A laptop Rack is started with `convox start` which requires a working Docker environment. To setup a Docker environment, see the [Docker Machine](https://docs.docker.com/machine/) docs. You can then run the project:\n+\n+```\n+$ docker-machine start default\n+$ eval $(docker-machine env default)\n+\n+$ convox start\n+RUNNING: docker build -t convox-start-icytafnqqb /Users/noah/go/src/github.com/convox/rack\n+web      | running: docker run -i --name rack-web...\n+web      | [negroni] listening on :3000\n+```\n+\n+Now you can log into the development Rack API and interact with your Convox resources:\n+\n+```\n+$ convox login $(docker-machine ip default)\n+\n+$ convox instances\n+ID          AGENT  STATUS  STARTED      PS  CPU    MEM   \n+i-6cf228f7  on     active  2 hours ago  4   0.00%  10.42%\n+i-146c2f97  on     active  2 hours ago  1   0.00%  3.21% \n+i-c7de605c  on     active  2 hours ago  0   0.00%  0.00% \n+```\n+\n+## Golang Unit Test Suite\n+\n+Rack has a suite of Golang unit and integration tests that offer very fast feedback (< 1 minute) about system correctness. They require a running Docker environment.\n+\n+```\n+$ make test\n+docker info >/dev/null\n+go get -t ./...\n+env PROVIDER=test go test -v -cover ./...\n+=== RUN   TestGitUrl\n+=== RUN   TestDockerCompose\n+=== RUN   TestEnvFile\n+...\n+\n+$ echo $?\n+0\n+```\n+\n+GitHub and Travis CI are configured to require that tests are passing before PR can be merged.\n+\n+The most complex tests, such as `TestProcessesListWithDetached` setup a stub AWS and Docker httptest web servers to simulate various request and response cycles. This can be challenging to write but represent a very powerful way to verify Convox behavior.","path":"Development.md","position":134,"original_position":134,"commit_id":"18d4c58f417388e8e630ede8d9faafa6c35baf96","original_commit_id":"12cee93dc799574b037d4e74745c91633eba70cf","user":{"login":"yuvaly","id":17435370,"avatar_url":"https://avatars.githubusercontent.com/u/17435370?v=3","gravatar_id":"","url":"https://api.github.com/users/yuvaly","html_url":"https://github.com/yuvaly","followers_url":"https://api.github.com/users/yuvaly/followers","following_url":"https://api.github.com/users/yuvaly/following{/other_user}","gists_url":"https://api.github.com/users/yuvaly/gists{/gist_id}","starred_url":"https://api.github.com/users/yuvaly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yuvaly/subscriptions","organizations_url":"https://api.github.com/users/yuvaly/orgs","repos_url":"https://api.github.com/users/yuvaly/repos","events_url":"https://api.github.com/users/yuvaly/events{/privacy}","received_events_url":"https://api.github.com/users/yuvaly/received_events","type":"User","site_admin":false},"body":"I think it should be 'represents'. ","created_at":"2016-03-28T23:43:49Z","updated_at":"2016-03-28T23:43:49Z","html_url":"https://github.com/convox/rack/pull/478#discussion_r57652824","pull_request_url":"https://api.github.com/repos/convox/rack/pulls/478","_links":{"self":{"href":"https://api.github.com/repos/convox/rack/pulls/comments/57652824"},"html":{"href":"https://github.com/convox/rack/pull/478#discussion_r57652824"},"pull_request":{"href":"https://api.github.com/repos/convox/rack/pulls/478"}}},"pull_request":{"url":"https://api.github.com/repos/convox/rack/pulls/478","id":63939434,"html_url":"https://github.com/convox/rack/pull/478","diff_url":"https://github.com/convox/rack/pull/478.diff","patch_url":"https://github.com/convox/rack/pull/478.patch","issue_url":"https://api.github.com/repos/convox/rack/issues/478","number":478,"state":"open","locked":false,"title":"Readme changes and new Development Guide","user":{"login":"nzoschke","id":147410,"avatar_url":"https://avatars.githubusercontent.com/u/147410?v=3","gravatar_id":"","url":"https://api.github.com/users/nzoschke","html_url":"https://github.com/nzoschke","followers_url":"https://api.github.com/users/nzoschke/followers","following_url":"https://api.github.com/users/nzoschke/following{/other_user}","gists_url":"https://api.github.com/users/nzoschke/gists{/gist_id}","starred_url":"https://api.github.com/users/nzoschke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nzoschke/subscriptions","organizations_url":"https://api.github.com/users/nzoschke/orgs","repos_url":"https://api.github.com/users/nzoschke/repos","events_url":"https://api.github.com/users/nzoschke/events{/privacy}","received_events_url":"https://api.github.com/users/nzoschke/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-03-23T19:29:17Z","updated_at":"2016-03-28T23:43:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5b1f3d6c8ada1ec701d5d661324af491f981ab4d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/convox/rack/pulls/478/commits","review_comments_url":"https://api.github.com/repos/convox/rack/pulls/478/comments","review_comment_url":"https://api.github.com/repos/convox/rack/pulls/comments{/number}","comments_url":"https://api.github.com/repos/convox/rack/issues/478/comments","statuses_url":"https://api.github.com/repos/convox/rack/statuses/18d4c58f417388e8e630ede8d9faafa6c35baf96","head":{"label":"convox:readme","ref":"readme","sha":"18d4c58f417388e8e630ede8d9faafa6c35baf96","user":{"login":"convox","id":10547780,"avatar_url":"https://avatars.githubusercontent.com/u/10547780?v=3","gravatar_id":"","url":"https://api.github.com/users/convox","html_url":"https://github.com/convox","followers_url":"https://api.github.com/users/convox/followers","following_url":"https://api.github.com/users/convox/following{/other_user}","gists_url":"https://api.github.com/users/convox/gists{/gist_id}","starred_url":"https://api.github.com/users/convox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convox/subscriptions","organizations_url":"https://api.github.com/users/convox/orgs","repos_url":"https://api.github.com/users/convox/repos","events_url":"https://api.github.com/users/convox/events{/privacy}","received_events_url":"https://api.github.com/users/convox/received_events","type":"Organization","site_admin":false},"repo":{"id":42454540,"name":"rack","full_name":"convox/rack","owner":{"login":"convox","id":10547780,"avatar_url":"https://avatars.githubusercontent.com/u/10547780?v=3","gravatar_id":"","url":"https://api.github.com/users/convox","html_url":"https://github.com/convox","followers_url":"https://api.github.com/users/convox/followers","following_url":"https://api.github.com/users/convox/following{/other_user}","gists_url":"https://api.github.com/users/convox/gists{/gist_id}","starred_url":"https://api.github.com/users/convox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convox/subscriptions","organizations_url":"https://api.github.com/users/convox/orgs","repos_url":"https://api.github.com/users/convox/repos","events_url":"https://api.github.com/users/convox/events{/privacy}","received_events_url":"https://api.github.com/users/convox/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/convox/rack","description":"Open-source PaaS on AWS","fork":false,"url":"https://api.github.com/repos/convox/rack","forks_url":"https://api.github.com/repos/convox/rack/forks","keys_url":"https://api.github.com/repos/convox/rack/keys{/key_id}","collaborators_url":"https://api.github.com/repos/convox/rack/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/convox/rack/teams","hooks_url":"https://api.github.com/repos/convox/rack/hooks","issue_events_url":"https://api.github.com/repos/convox/rack/issues/events{/number}","events_url":"https://api.github.com/repos/convox/rack/events","assignees_url":"https://api.github.com/repos/convox/rack/assignees{/user}","branches_url":"https://api.github.com/repos/convox/rack/branches{/branch}","tags_url":"https://api.github.com/repos/convox/rack/tags","blobs_url":"https://api.github.com/repos/convox/rack/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/convox/rack/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/convox/rack/git/refs{/sha}","trees_url":"https://api.github.com/repos/convox/rack/git/trees{/sha}","statuses_url":"https://api.github.com/repos/convox/rack/statuses/{sha}","languages_url":"https://api.github.com/repos/convox/rack/languages","stargazers_url":"https://api.github.com/repos/convox/rack/stargazers","contributors_url":"https://api.github.com/repos/convox/rack/contributors","subscribers_url":"https://api.github.com/repos/convox/rack/subscribers","subscription_url":"https://api.github.com/repos/convox/rack/subscription","commits_url":"https://api.github.com/repos/convox/rack/commits{/sha}","git_commits_url":"https://api.github.com/repos/convox/rack/git/commits{/sha}","comments_url":"https://api.github.com/repos/convox/rack/comments{/number}","issue_comment_url":"https://api.github.com/repos/convox/rack/issues/comments{/number}","contents_url":"https://api.github.com/repos/convox/rack/contents/{+path}","compare_url":"https://api.github.com/repos/convox/rack/compare/{base}...{head}","merges_url":"https://api.github.com/repos/convox/rack/merges","archive_url":"https://api.github.com/repos/convox/rack/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/convox/rack/downloads","issues_url":"https://api.github.com/repos/convox/rack/issues{/number}","pulls_url":"https://api.github.com/repos/convox/rack/pulls{/number}","milestones_url":"https://api.github.com/repos/convox/rack/milestones{/number}","notifications_url":"https://api.github.com/repos/convox/rack/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/convox/rack/labels{/name}","releases_url":"https://api.github.com/repos/convox/rack/releases{/id}","deployments_url":"https://api.github.com/repos/convox/rack/deployments","created_at":"2015-09-14T14:41:30Z","updated_at":"2016-03-28T22:37:20Z","pushed_at":"2016-03-28T23:36:22Z","git_url":"git://github.com/convox/rack.git","ssh_url":"git@github.com:convox/rack.git","clone_url":"https://github.com/convox/rack.git","svn_url":"https://github.com/convox/rack","homepage":"https://convox.com","size":46575,"stargazers_count":175,"watchers_count":175,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":34,"mirror_url":null,"open_issues_count":84,"forks":34,"open_issues":84,"watchers":175,"default_branch":"master"}},"base":{"label":"convox:master","ref":"master","sha":"0214ddac5e03955a4265c9ae615aed49ee3babd3","user":{"login":"convox","id":10547780,"avatar_url":"https://avatars.githubusercontent.com/u/10547780?v=3","gravatar_id":"","url":"https://api.github.com/users/convox","html_url":"https://github.com/convox","followers_url":"https://api.github.com/users/convox/followers","following_url":"https://api.github.com/users/convox/following{/other_user}","gists_url":"https://api.github.com/users/convox/gists{/gist_id}","starred_url":"https://api.github.com/users/convox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convox/subscriptions","organizations_url":"https://api.github.com/users/convox/orgs","repos_url":"https://api.github.com/users/convox/repos","events_url":"https://api.github.com/users/convox/events{/privacy}","received_events_url":"https://api.github.com/users/convox/received_events","type":"Organization","site_admin":false},"repo":{"id":42454540,"name":"rack","full_name":"convox/rack","owner":{"login":"convox","id":10547780,"avatar_url":"https://avatars.githubusercontent.com/u/10547780?v=3","gravatar_id":"","url":"https://api.github.com/users/convox","html_url":"https://github.com/convox","followers_url":"https://api.github.com/users/convox/followers","following_url":"https://api.github.com/users/convox/following{/other_user}","gists_url":"https://api.github.com/users/convox/gists{/gist_id}","starred_url":"https://api.github.com/users/convox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convox/subscriptions","organizations_url":"https://api.github.com/users/convox/orgs","repos_url":"https://api.github.com/users/convox/repos","events_url":"https://api.github.com/users/convox/events{/privacy}","received_events_url":"https://api.github.com/users/convox/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/convox/rack","description":"Open-source PaaS on AWS","fork":false,"url":"https://api.github.com/repos/convox/rack","forks_url":"https://api.github.com/repos/convox/rack/forks","keys_url":"https://api.github.com/repos/convox/rack/keys{/key_id}","collaborators_url":"https://api.github.com/repos/convox/rack/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/convox/rack/teams","hooks_url":"https://api.github.com/repos/convox/rack/hooks","issue_events_url":"https://api.github.com/repos/convox/rack/issues/events{/number}","events_url":"https://api.github.com/repos/convox/rack/events","assignees_url":"https://api.github.com/repos/convox/rack/assignees{/user}","branches_url":"https://api.github.com/repos/convox/rack/branches{/branch}","tags_url":"https://api.github.com/repos/convox/rack/tags","blobs_url":"https://api.github.com/repos/convox/rack/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/convox/rack/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/convox/rack/git/refs{/sha}","trees_url":"https://api.github.com/repos/convox/rack/git/trees{/sha}","statuses_url":"https://api.github.com/repos/convox/rack/statuses/{sha}","languages_url":"https://api.github.com/repos/convox/rack/languages","stargazers_url":"https://api.github.com/repos/convox/rack/stargazers","contributors_url":"https://api.github.com/repos/convox/rack/contributors","subscribers_url":"https://api.github.com/repos/convox/rack/subscribers","subscription_url":"https://api.github.com/repos/convox/rack/subscription","commits_url":"https://api.github.com/repos/convox/rack/commits{/sha}","git_commits_url":"https://api.github.com/repos/convox/rack/git/commits{/sha}","comments_url":"https://api.github.com/repos/convox/rack/comments{/number}","issue_comment_url":"https://api.github.com/repos/convox/rack/issues/comments{/number}","contents_url":"https://api.github.com/repos/convox/rack/contents/{+path}","compare_url":"https://api.github.com/repos/convox/rack/compare/{base}...{head}","merges_url":"https://api.github.com/repos/convox/rack/merges","archive_url":"https://api.github.com/repos/convox/rack/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/convox/rack/downloads","issues_url":"https://api.github.com/repos/convox/rack/issues{/number}","pulls_url":"https://api.github.com/repos/convox/rack/pulls{/number}","milestones_url":"https://api.github.com/repos/convox/rack/milestones{/number}","notifications_url":"https://api.github.com/repos/convox/rack/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/convox/rack/labels{/name}","releases_url":"https://api.github.com/repos/convox/rack/releases{/id}","deployments_url":"https://api.github.com/repos/convox/rack/deployments","created_at":"2015-09-14T14:41:30Z","updated_at":"2016-03-28T22:37:20Z","pushed_at":"2016-03-28T23:36:22Z","git_url":"git://github.com/convox/rack.git","ssh_url":"git@github.com:convox/rack.git","clone_url":"https://github.com/convox/rack.git","svn_url":"https://github.com/convox/rack","homepage":"https://convox.com","size":46575,"stargazers_count":175,"watchers_count":175,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":34,"mirror_url":null,"open_issues_count":84,"forks":34,"open_issues":84,"watchers":175,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/convox/rack/pulls/478"},"html":{"href":"https://github.com/convox/rack/pull/478"},"issue":{"href":"https://api.github.com/repos/convox/rack/issues/478"},"comments":{"href":"https://api.github.com/repos/convox/rack/issues/478/comments"},"review_comments":{"href":"https://api.github.com/repos/convox/rack/pulls/478/comments"},"review_comment":{"href":"https://api.github.com/repos/convox/rack/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/convox/rack/pulls/478/commits"},"statuses":{"href":"https://api.github.com/repos/convox/rack/statuses/18d4c58f417388e8e630ede8d9faafa6c35baf96"}}}}