HACKING.md
c6b0a135
 Hacking on OpenShift
 ====================
d5b5894e
 
e3bb13a1
 ## Building a Release
 
 To build an OpenShift release you run the `hack/build-release.sh` script on a system with Docker, which
 will create a build environment image and then execute a cross platform Go build within it. The build
 output will be copied to `_output/releases` as a set of tars containing each version. It will also build
 the `openshift/origin-base` image which is the common parent image for all OpenShift Docker images.
 
     $ hack/build-release.sh
 
ac49969c
 NOTE:  Only committed code is built.
 
e3bb13a1
 Once the release has been built the official Docker images can be generated with `hack/build-images.sh`.
 The resulting images can then be pushed to a Docker registry.
 
     $ hack/build-images.sh
 
ac49969c
 NOTE:  You only need to run this script if your code changes are part of any images OpenShift runs internally
 such as origin-sti-builder, origin-docker-builder,  origin-deployer, etc.
 
 To build the base and release images, run:
e3bb13a1
 
     $ hack/build-base-images.sh
 
39e50d3e
 Once a release has been created, it can be pushed:
 
     $ hack/push-release.sh
 
 To cut an official tag release, we generally use the images built by [ci.openshift.redhat.com](https://ci.openshift.redhat.com)
0b8e6dad
 under the devenv_ami job.
39e50d3e
 
0b8e6dad
 1. Create a new git tag `git tag vX.X.X -a -m "vX.X.X" HEAD`
39e50d3e
 2. Push the tag to GitHub `git push origin --tags` where `origin` is `github.com/openshift/origin.git`
0b8e6dad
 3. Run the "devenv_ami" job
 4. Once the images are pushed to the repository, run `OS_PUSH_TAG="vX.X.X" hack/push-release.sh`. Your tag must match the Git tag.
39e50d3e
 5. Upload the binary artifacts generated by that build to GitHub release page
 6. Send an email to the dev list, including the important changes prior to the release.
 
 We generally cut a release before disruptive changes land.
 
e3bb13a1
 
d5b5894e
 ## Test Suites
 
c6b0a135
 OpenShift uses three levels of testing - unit tests, integration test, and end-to-end tests (much
d5b5894e
 like Kubernetes).
 
 ### Unit tests
 
 Unit tests follow standard Go conventions and are intended to test the behavior and output of a
 single package in isolation. All code is expected to be easily testable with mock interfaces and
 stubs, and when they are not it usually means that there's a missing interface or abstraction in the
 code. A unit test should focus on testing that branches and error conditions are properly returned
 and that the interface and code flows work as described. Unit tests can depend on other packages but
 should not depend on other components (an API test should not be writing to etcd).
 
c6b0a135
 The unit tests for an entire package should not take more than 0.5s to run, and if they do, are
d5b5894e
 probably not really unit tests or need to be rewritten to avoid sleeps or pauses. Coverage on a unit
 test should be above 70% unless the units are a special case.
 
 See `pkg/template/generator` for examples of unit tests. Unit tests should follow Go conventions.
 
c6b0a135
 Run the unit tests with:
d5b5894e
 
     $ hack/test-go.sh
 
c6b0a135
 or an individual package unit test with:
d5b5894e
 
     $ hack/test-go.sh pkg/build
 
 To run only a certain regex of tests in a package, use:
 
     $ hack/test-go.sh pkg/build -test.run=SynchronizeBuildRunning
 
 To get verbose output add `-v` to the end:
 
     $ hack/test-go.sh pkg/build -test.run=SynchronizeBuildRunning -v
 
 To run all tests with verbose output:
 
     $ hack/test-go.sh "" -v
 
a034c68a
 To enable running the kubernetes unit tests:
 
     $ TEST_KUBE=1 hack/test-go.sh
 
 To run unit test for an individual kubernetes package:
 
83c702b4
     $ TEST_KUBE=1 hack/test-go.sh Godeps/_workspace/src/k8s.io/kubernetes/examples
a034c68a
 
c6b0a135
 To turn off or change the coverage mode, which is `-cover -covermode=atomic` by default, use:
 
     $ KUBE_COVER="" hack/test-go.sh
 
 To run tests without the go race detector, which is on by default, use:
 
     $ KUBE_RACE="" hack/test-go.sh
 
dfde1e63
 A line coverage report is run by default when testing a single package.
 To create a coverage report for all packages:
 
     $ OUTPUT_COVERAGE=true hack/test-go.sh pkg/build
 
d5b5894e
 ### Integration tests
 
 Integration tests cover multiple components acting together (generally, 2 or 3). These tests should
 focus on ensuring that naturally related components work correctly.  They should not be extensively
 testing branches or error conditions inside packages (that's what unit tests do), but they should
 validate that important success and error paths work across layers (especially when errors are being
 converted from lower level errors). Integration tests should not be testing details of the
4bd768c8
 inter-component connections - API tests should not test that the JSON serialized to the wire is
d5b5894e
 correctly converted back and forth (unit test responsibility), but they should test that those
 connections have the expected outcomes. The underlying goal of integration tests is to wire together
 the most important components in isolation. Integration tests should be as fast as possible in order
 to enable them to be run repeatedly during testing.  Integration tests that take longer than 0.5s
 are probably trying to test too much together and should be reorganized into separate tests.
 Integration tests should generally be written so that they are starting from a clean slate, but if
 that involves costly setup those components should be tested in isolation.
 
 We break integration tests into two categories, those that use Docker and those that do not.  In
 general, high-level components that depend on the behavior of code running inside a Docker container
 should have at least one or two integration tests that test all the way down to Docker, but those
 should be part of their own test suite.  Testing the API and high level API functions should
 generally not depend on calling into Docker. They are denoted by special test tags and should be in
 their own files so we can selectively build them.
 
 All integration tests are located under `test/integration/*`. All integration tests must set the
 `integration` build tag at the top of their source file, and also declare whether they need etcd
44748a0d
 with the `etcd` build tag and whether they need Docker with the `docker` build tag. For
4bd768c8
 special function sets please create sub directories like `test/integration/deployimages`.
d5b5894e
 
 Run the integration tests with:
 
     $ hack/test-integration.sh
 
 The script launches an instance of etcd and then invokes the integration tests. If you need to
a57ea3ac
 execute a subset of integration tests, run:
d5b5894e
 
a57ea3ac
     $ hack/test-integration.sh <regex>
97036f78
 
a57ea3ac
 Where `<regex>` is some regular expression that matches the names of all of the tests you want to run.
 The regular expression is passed into `grep -E`, so ensure that the syntax or features you use are supported.
 The default regular expression used is `Test`, which matches all tests.
d5b5894e
 
5bcc9176
 Each integration function is executed in its own process so that it cleanly shuts down any background
 goroutines. You will not be able to run more than a single test within a single process.
 
d5b5894e
 There is a CLI integration test suite which covers general non-Docker functionality of the CLI tool
 working against the API. Run it with:
 
     $ hack/test-cmd.sh
 
 ### End-to-End (e2e) Tests
 
 The final test category is end to end tests (e2e) which should verify a long set of flows in the
 product as a user would see them.  Two e2e tests should not overlap more than 10% of function, and
 are not intended to test error conditions in detail. The project examples should be driven by e2e
 tests. e2e tests can also test external components working together.
 
 End to end tests should be Go tests with the build tag `e2e` in the `test/e2e` directory.
 
 Run the end to end tests with:
 
b4cdf3d7
     $ hack/test-end-to-end.sh
d5b5894e
 
 
f04c63ff
 ## Installing Godep
 
d5b5894e
 OpenShift and Kubernetes use [Godep](https://github.com/tools/godep) for dependency management.
 Godep allows versions of dependent packages to be locked at a specific commit by *vendoring* them
 (checking a copy of them into `Godeps/_workspace/`).  This means that everything you need for
46aa1236
 OpenShift is checked into this repository.  To install `godep` locally run:
f04c63ff
 
     $ go get github.com/tools/godep
 
 If you are not updating packages you should not need godep installed.
 
25012b65
 ## Cherry-picking an upstream commit into Origin
 
 You can use `hack/cherry-pick.sh` to generate patches for Origin from upstream commits. To use
 this command, be sure to setup remote branches like https://gist.github.com/piscisaureus/3342247
 so that `git show origin/pr/<number>` displays information about your branch after a `git fetch`.
 You must also have the Kubernetes repository checked out in your GOPATH (visible as `../../../k8s.io/kubernetes`)
4bd768c8
 and have no modified or uncommitted files in either repository.
25012b65
 
 To pull an upstream commit, run:
 
     $ hack/cherry-pick.sh <pr_number>
 
 This will attempt to create a patch from the current Kube rebase version in Origin that contains
 the commits added in the PR. If the PR has already been merged to the Kube version, you'll get an
 error. If there are conflicts, you'll have to resolve them in the upstream repo, then hit ENTER
 to continue. The end result will be a single commit in your Origin repo that contains the changes.
 
 If you want to run without a rebase option, set `NO_REBASE=1` before the command is run. You can
 also specify a commit range directly with:
 
     $ hack/cherry-pick.sh origin/master...<some_branch>
 
 All upstream commits should have a commit message where the first line is:
 
     UPSTREAM: <PR number|drop|carry>: <short description>
 
 `drop` indicates the commit should be removed during the next rebase. `carry` means that the change
 cannot go into upstream, and we should continue to use it during the next rebase.
 
cf28c106
 You can also target repositories other than Kube by setting `UPSTREAM_REPO` and `UPSTREAM_PACKAGE`
 env vars.  `UPSTREAM_REPO` should be the full name of the Git repo as Go sees it, i.e.
 `github.com/coreos/etcd`, and `UPSTREAM_PACKAGE` must be a package inside that repo that is
 currently part of the Godeps.json file.  Example:
 
     $ UPSTREAM_REPO=github.com/coreos/etcd UPSTREAM_PACKAGE=store hack/cherry-pick.sh <pr_number>
 
35cb35a3
 By default `hack/cherry-pick.sh` uses git remote named `origin` to fetch kubernetes repository,
 if your git configuration is different, you can pass the git remote name by setting `UPSTREAM_REMOTE` env var:
 
     $ UPSTREAM_REMOTE=upstream hack/cherry-pick.sh <pr_number>
 
cf28c106
 ## Moving a commit you developed in Origin to an upstream
 
 The `hack/move-upstream.sh` script takes the current feature branch, finds any changes to the
 requested upstream project (as defined by `UPSTREAM_REPO` and `UPSTREAM_PACKAGE`) that differ
 from `origin/master`, and then creates a new commit in that upstream project on a branch with
 the same name as your current branch.
 
 For example, to upstream a commit to OpenShift source-to-image while working from Origin:
 
     $ git checkout my_feature_branch_in_origin
     $ git log --oneline
     70ffe7e Docker and STI builder support binary extraction
     75a22de UPSTREAM: <sti>: Allow prepared directories to be passed to STI
     86eefdd UPSTREAM: 14618: Refactor exec to allow reuse from server
 
     # we want to move our STI changes to upstream
     $ UPSTREAM_REPO=github.com/openshift/source-to-image UPSTREAM_PACKAGE=pkg/api hack/move-upstream.sh
     ...
 
     # All changes to source-to-image in Godeps/. are now in a commit UPSTREAMED in s2i repo
 
     $ cd ../source-to-image
     $ git log --oneline
     c0029f6 UPSTREAMED
     ... # older commits
 
 The default is to work against Kube.
 
25012b65
 
f21d79e7
 ## Updating Kubernetes from upstream
 
 There are a few steps involved in rebasing Origin to a new version of Kubernetes. We need to make sure
 that not only the Kubernetes packages were updated correctly into `Godeps`, but also that *all tests are
 still running without errors* and *code changes, refactorings or the inclusion/removal of attributes
46aa1236
 were properly reflected* in the Origin codebase.
f21d79e7
 
 ### 1. Preparation
 
 Before you begin, make sure you have both [openshift/origin](https://github.com/openshift/origin) and
797bcb44
 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) in your $GOPATH. You may want to work
 on a separate $GOPATH just for the rebase:
f21d79e7
 
 ```
 $ go get github.com/openshift/origin
83c702b4
 $ go get k8s.io/kubernetes
f21d79e7
 ```
 
 Check out the version of Kubernetes you want to rebase as a branch or tag named `stable_proposed` in
3dbf26a7
 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). For example,
f21d79e7
 if you are going to rebase the latest `master` of Kubernetes:
 
 ```
83c702b4
 $ cd $GOPATH/src/k8s.io/kubernetes
f21d79e7
 $ git checkout master
 $ git pull
 $ git checkout -b stable_proposed
 ```
 
 ### 2. Rebase Origin to the new Kubernetes version
 
 #### 2.1. First option (preferred): using the rebase-kube.sh script
 
 If all requirements described in *Preparation* were correctly attended, you should not have any trouble
46aa1236
 with rebasing the Kubernetes code using the script that automates this process.
f21d79e7
 
 ```
 $ cd $GOPATH/src/github.com/openshift/origin
 $ hack/rebase-kube.sh
 ```
 
46aa1236
 Read over the changes with `git status` and make sure it looks reasonable. Check specially the
f21d79e7
 `Godeps/Godeps.json` file to make sure no dependency is unintentionally missing.
 
83c702b4
 Commit using the message `bump(k8s.io/kubernetes):<commit SHA>`, where
46aa1236
 `<commit SHA>` is the commit id for the Kubernetes version we are including in our Godeps. It can be
f21d79e7
 found in our `Godeps/Godeps.json` in the declaration of any Kubernetes package.
 
 #### 2.2. Second option: manually
 
46aa1236
 If for any reason you had trouble rebasing using the script, you may need to to do it manually.
 After following all requirements described in the *Preparation* topic, you will need to run
f21d79e7
 `godep restore` from both the Origin and the Kubernetes directories and then `godep save ./...`
 from the Origin directory. Follow these steps:
 
 1. `$ cd $GOPATH/src/github.com/openshift/origin`
46aa1236
 2. `make clean ; godep restore` will restore the package versions specified in the `Godeps/Godeps.json`
f21d79e7
 of Origin to your GOPATH.
83c702b4
 2. `$ cd $GOPATH/src/k8s.io/kubernetes`
46aa1236
 3. `$ git checkout stable_proposed` will checkout the desired version of Kubernetes as branched in
f21d79e7
 *Preparation*.
46aa1236
 4. `$ godep restore` will restore the package versions specified in the `Godeps/Godeps.json`
f21d79e7
 of Kubernetes to your GOPATH.
 5. `$ cd $GOPATH/src/github.com/openshift/origin`.
46aa1236
 6. `$ make clean ; godep save ./...` will save a list of the checked-out dependencies to the file
f21d79e7
 `Godeps/Godeps.json`, and copy their source code into `Godeps/_workspace`.
46aa1236
 7. If in the previous step godep complaints about the checked out revision of a package being different
 than the wanted revision, this probably means there are new packages in Kubernetes that we need to add.
 Do a `godep save <pkgname>` with the package specified by the error message and then `$ godep save ./...`
f21d79e7
 again.
46aa1236
 8. Read over the changes with `git status` and make sure it looks reasonable. Check specially the
 `Godeps/Godeps.json` file to make sure no dependency is unintentionally missing. The whole Godeps
f21d79e7
 directory will be added to version control, including `_workspace`.
83c702b4
 9. Commit using the message `bump(k8s.io/kubernetes):<commit SHA>`, where
46aa1236
 `<commit SHA>` is the commit id for the Kubernetes version we are including in our Godeps. It can be
f21d79e7
 found in our `Godeps/Godeps.json` in the declaration of any Kubernetes package.
 
 If in the process of rebasing manually you found any corner case not attended by the `hack/rebase-kube.sh`
 script, make sure you update it accordingly to help future rebases.
 
 ### 3. cherry-pick upstream changes pushed to the Origin repo
 
46aa1236
 Eventually during the development cycle we introduce changes to dependencies right in the Origin
 repository. This is not a largely recommended practice, but it's useful if we need something that,
 for example, is in the Kubernetes repository but we are not doing a rebase yet. So, when doing the next
 rebase, we need to make sure we get all these changes otherwise they will be overridden by `godep save`.
f21d79e7
 
46aa1236
 1. Check the `Godeps` directory [commits history](https://github.com/openshift/origin/commits/master/Godeps)
 for commits tagged with the *UPSTREAM* keyword. We will need to cherry-pick *all UPSTREAM commits since
 the last Kubernetes rebase* (remember you can find the last rebase commit looking for a message like
83c702b4
 `bump(k8s.io/kubernetes):...`).
f21d79e7
 2. For every commit tagged UPSTREAM, do `git cherry-pick <commit SHA>`.
46aa1236
 3. Notice that eventually the cherry-pick will be empty. This probably means the given change were
f21d79e7
 already merged in Kubernetes and we don't need to specifically add it to our Godeps. Nice!
46aa1236
 4. Read over the commit history and make sure you have every UPSTREAM commit since the last rebase
f21d79e7
 (except only for the empty ones).
 
 ### 4. Refactor Origin to be compliant with upstream changes
 
46aa1236
 After making sure we have all the dependencies in place and up-to-date, we need to work in the Origin
 codebase to make sure the compilation is not broken, all tests pass and it's compliant with any
 refactorings, architectural changes or behavior changes introduced in Kubernetes. Make sure:
f21d79e7
 
 1. `make clean ; hack/build-go.sh` compiles without errors and the standalone server starts correctly.
797bcb44
 1. all of our generated code is up to date by running all `hack/update-*` scripts.
 1. `hack/verify-open-ports.sh` runs without errors.
35cb35a3
 1. `hack/copy-kube-artifacts.sh` so Kubernetes tests can be fully functional. The diff resulting from this script should be squashed into the Kube bump commit.
a034c68a
 2. `TEST_KUBE=1 hack/test-go.sh` runs without errors.
f21d79e7
 3. `hack/test-cmd.sh` runs without errors.
 3. `hack/test-integration.sh` runs without errors.
46aa1236
 3. `hack/test-end-to-end.sh` runs without errors.
f1a00d40
     See *Building a Release* above for setting up the environment for the *test-end-to-end.sh* tests.
f21d79e7
 
46aa1236
 It is helpful to look at the Kubernetes commit history to be aware of the major topics. Although it
f21d79e7
 can potentially break or change any part of Origin, the most affected parts are usually:
 
 1. https://github.com/openshift/origin/blob/master/pkg/cmd/server/start.go
 2. https://github.com/openshift/origin/blob/master/pkg/cmd/server/kubernetes/master.go
 3. https://github.com/openshift/origin/blob/master/pkg/cmd/server/origin/master.go
 4. https://github.com/openshift/origin/blob/master/pkg/cmd/cli/cmd/factory.go
 5. https://github.com/openshift/origin/blob/master/pkg/cmd/cli/cli.go
 6. https://github.com/openshift/origin/blob/master/pkg/api/meta/multimapper.go
 
 Place all your changes in a commit called "Refactor to match changes upstream".
 
 ### 5. Pull request
 
 A typical pull request for your Kubernetes rebase will contain:
 
797bcb44
 1. One commit for the Kuberentes Godeps bump (`bump(k8s.io/kubernetes):<commit SHA>`).
 2. Zero, one, or more bump commits for any **shared** dependencies between Origin and Kubernetes that have been bumped. Any transitive dependencies coming from Kubernetes should be squashed in the Kube bump commit.
 3. Zero, one, or more cherry-picked commits tagged UPSTREAM.
 4. One commit "Boring refactor to match changes upstream" that includes boring changes like imports rewriting, etc.
 5. One commit "Interesting refactor to match changes upstream" that includes interesting changes like new plugins or controller changes.
f21d79e7
 
 ## Updating other Godeps from upstream
f04c63ff
 
d5b5894e
 To update to a new version of a dependency that's not already included in Kubernetes, checkout the
 correct version in your GOPATH and then run `godep save <pkgname>`.  This should create a new
60d2eb40
 version of `Godeps/Godeps.json`, and update `Godeps/_workspace/src`.  Create a commit that includes
 both of these changes with message `bump(<pkgname>): <pkgcommit>`.
f04c63ff
 
da3b06d1
 ## Troubleshooting
 
46aa1236
 If you run into difficulties running OpenShift, start by reading through the
 [troubleshooting guide](https://github.com/openshift/origin/blob/master/docs/debugging-openshift.md).
fe6b7dbe
 
 ## RPM Packaging
 
 A specfile is included in this repo which can be used to produce RPMs including
 the openshift binary. While the specfile will be kept up to date with build
 requirements the version is not updated. You will need to either update the
 Version, %commit, and %ldflags values on your own or you may use
 [tito](https://github.com/dgoodwin/tito) to build
 and tag releases.
56df56a7
 
 ## Swagger API Documentation
 
 OpenShift and Kubernetes integrate with the [Swagger 2.0 API framework](http://swagger.io) which aims to make it easier to document and write clients for RESTful APIs.  When you start OpenShift, the Swagger API endpoint is exposed at `https://localhost:8443/swaggerapi`. The Swagger UI makes it easy to view your documentation - to view the docs for your local version of OpenShift start the server with CORS enabled:
 
     $ openshift start --cors-allowed-origins=.*
 
 and then browse to http://openshift3swagger-claytondev.rhcloud.com (which runs a copy of the Swagger UI that points to localhost:8080 by default).  Expand the operations available on v1beta3 to see the schemas (and to try the API directly).
 
 Note: Hosted API documentation can be found [here](http://docs.openshift.org/latest/rest_api/openshift_v1.html).
c91b857b
 
 
 ## Performance debugging
 
 OpenShift integrates the go `pprof` tooling to make it easy to capture CPU and heap dumps for running systems.  The following modes are available for the `openshift` binary (including all the CLI variants):
 
 * `OPENSHIFT_PROFILE` environment variable:
   * `cpu` - will start a CPU profile on startup and write `./cpu.pprof`.  Contains samples for the entire run at the native sampling resolution (100hz). Note: CPU profiling for Go does not currently work on Mac OS X - the stats are not correctly sampled
   * `mem` - generate a running heap dump that tracks allocations to `./mem.pprof`
   * `web` - start the pprof webserver in process at http://127.0.0.1:6060/debug/pprof (you can open this in a browser)
 
97036f78
 In order to start the server in CPU profiling mode, run:
a57ea3ac
 
97036f78
     $ OPENSHIFT_PROFILE=cpu sudo ./_output/local/bin/linux/amd64/openshift start
c91b857b
 
d8282817
 Or, if running OpenShift under systemd, append this to /etc/sysconfig/openshift-master
 
     OPENSHIFT_PROFILE=cpu
 
 To view profiles, you use [pprof](http://goog-perftools.sourceforge.net/doc/cpu_profiler.html) which is part of `go tool`.  You must pass the binary you are debugging (for symbols) and a captured pprof.  For instance, to view a `cpu` profile from above, you would run OpenShift to completion, and then run:
c91b857b
 
97036f78
     $ go tool pprof ./_output/local/bin/linux/amd64/openshift cpu.pprof
d8282817
     or
     $ go tool pprof /bin/openshift /var/lib/openshift/cpu.pprof
c91b857b
 
 This will open the `pprof` shell, and you can then run:
 
     # see the top 20 results
     (pprof) top20
 
     # see the top 50 results
     (pprof) top50
 
     # show the top20 sorted by cumulative time
     (pprof) cum=true
     (pprof) top20
 
 to see the top20 CPU consuming fields or
 
     (pprof) web
 
 to launch a web browser window showing you where CPU time is going.
 
 `pprof` supports CLI arguments for looking at profiles in different ways - memory profiles by default show allocated space:
 
97036f78
     $ go tool pprof ./_output/local/bin/linux/amd64/openshift mem.pprof
c91b857b
 
 but you can also see the allocated object counts:
 
97036f78
     $ go tool pprof --alloc_objects ./_output/local/bin/linux/amd64/openshift mem.pprof
c91b857b
 
 Finally, when using the `web` profile mode, you can have the go tool directly fetch your profiles via HTTP:
 
     # for a 30s CPU trace
97036f78
     $ go tool pprof ./_output/local/bin/linux/amd64/openshift http://127.0.0.1:6060/debug/pprof/profile
c91b857b
 
     # for a snapshot heap dump at the current time, showing total allocations
97036f78
     $ go tool pprof --alloc_space ./_output/local/bin/linux/amd64/openshift http://127.0.0.1:6060/debug/pprof/heap
c91b857b
 
a57ea3ac
 See [debugging Go programs](https://golang.org/pkg/net/http/pprof/) for more info.  `pprof` has many modes and is very powerful (try `tree`) - you can pass a regex to many arguments to limit your results to only those samples that match the regex (basically the function name or the call stack).