| ... | ... |
@@ -7,7 +7,12 @@ FROM openshift/origin |
| 7 | 7 |
|
| 8 | 8 |
ADD bin/gitserver /usr/bin/gitserver |
| 9 | 9 |
ADD hooks/ /var/lib/git-hooks/ |
| 10 |
-RUN mkdir -p /var/lib/git |
|
| 10 |
+RUN mkdir -p /var/lib/git && \ |
|
| 11 |
+ mkdir -p /var/lib/gitconfig && \ |
|
| 12 |
+ chmod 777 /var/lib/gitconfig && \ |
|
| 13 |
+ ln -s /usr/bin/gitserver /usr/bin/gitrepo-buildconfigs |
|
| 14 |
+ADD gitconfig /var/lib/gitconfig/.gitconfig |
|
| 15 |
+ENV HOME=/var/lib/gitconfig |
|
| 11 | 16 |
VOLUME /var/lib/git |
| 12 | 17 |
|
| 13 | 18 |
ENTRYPOINT ["/usr/bin/gitserver"] |
| ... | ... |
@@ -1,16 +1,214 @@ |
| 1 | 1 |
Configurable Git Server |
| 2 | 2 |
======================= |
| 3 | 3 |
|
| 4 |
-This example provides automatic mirroring of Git repositories, intended |
|
| 5 |
-for use within a container or Kubernetes pod. It can clone repositories |
|
| 6 |
-from remote systems on startup as well as remotely register hooks. It |
|
| 7 |
-can automatically initialize and receive Git directories on push. |
|
| 8 |
- |
|
| 9 |
-In the more advanced modes, it can integrate with an OpenShift server to |
|
| 10 |
-automatically perform actions when new repositories are created, like |
|
| 11 |
-reading the build configs in the current namespace and performing |
|
| 12 |
-automatic mirroring of their input, and creating new build-configs when |
|
| 13 |
-content is pushed. |
|
| 14 |
- |
|
| 15 |
-The Dockerfile built by this example is published as |
|
| 16 |
-openshift/origin-gitserver |
|
| 17 | 4 |
\ No newline at end of file |
| 5 |
+Overview |
|
| 6 |
+-------- |
|
| 7 |
+ |
|
| 8 |
+This example git server is intended for use within a container or Kubernetes pod. |
|
| 9 |
+It can clone repositories from remote systems on startup as well as automatically |
|
| 10 |
+launch builds in an OpenShift project. It can automatically initialize and receive |
|
| 11 |
+Git directories on push. |
|
| 12 |
+ |
|
| 13 |
+Hooks can be customized to perform actions on push such as invoking `oc new-app` on a |
|
| 14 |
+repository's source. |
|
| 15 |
+ |
|
| 16 |
+The Dockerfile built by this example is published as openshift/origin-gitserver |
|
| 17 |
+ |
|
| 18 |
+Quick Start |
|
| 19 |
+----------- |
|
| 20 |
+ |
|
| 21 |
+Prerequisites: |
|
| 22 |
+ |
|
| 23 |
+* You have an OpenShift v3 server running |
|
| 24 |
+* You are logged in and have access to a project |
|
| 25 |
+* You have the `gitserver.yaml` from this directory |
|
| 26 |
+* You can create externally accessible routes on your server |
|
| 27 |
+ |
|
| 28 |
+### Deploy the Git Server |
|
| 29 |
+ |
|
| 30 |
+1. Create the Git Server |
|
| 31 |
+ |
|
| 32 |
+ ```sh |
|
| 33 |
+ $ oc create -f gitserver.yaml |
|
| 34 |
+ ``` |
|
| 35 |
+ |
|
| 36 |
+2. Grant `edit` access to the `git` service account |
|
| 37 |
+ |
|
| 38 |
+ ```sh |
|
| 39 |
+ $ oc policy add-role-to-user edit -z git |
|
| 40 |
+ ``` |
|
| 41 |
+ |
|
| 42 |
+ |
|
| 43 |
+### Push code to the Git Server |
|
| 44 |
+ |
|
| 45 |
+Code repositories can be initialized on the Git Server by either doing a 'git push' or |
|
| 46 |
+a 'git clone' of the repository. |
|
| 47 |
+ |
|
| 48 |
+ |
|
| 49 |
+1. Find your git server's URL |
|
| 50 |
+ |
|
| 51 |
+ If you have a working router, determine the host name of your git server by getting its route: |
|
| 52 |
+ |
|
| 53 |
+ ```sh |
|
| 54 |
+ $ oc get route git |
|
| 55 |
+ ``` |
|
| 56 |
+ |
|
| 57 |
+ In this case, the URL of your git server will be the host name used by the route; something like: |
|
| 58 |
+ |
|
| 59 |
+ ``` |
|
| 60 |
+ http://git-myproject.infra.openshift.com |
|
| 61 |
+ ``` |
|
| 62 |
+ |
|
| 63 |
+ Alternatively, if your router is not functional, you can port-forward the git-server pod to your local machine. |
|
| 64 |
+ In a separate shell window, execute the following: (You must leave the port-forward command running |
|
| 65 |
+ for the port to be forwarded to your machine) |
|
| 66 |
+ |
|
| 67 |
+ ``` |
|
| 68 |
+ $ oc get pods | grep git ## get the git server pod |
|
| 69 |
+ $ oc port-forward -p PODNAME 8080 ## start port-forward where PODNAME is the git server pod |
|
| 70 |
+ ``` |
|
| 71 |
+ |
|
| 72 |
+ In this case, the URL of your git server will be your local host: |
|
| 73 |
+ |
|
| 74 |
+ ``` |
|
| 75 |
+ http://localhost:8080 |
|
| 76 |
+ ``` |
|
| 77 |
+ |
|
| 78 |
+ |
|
| 79 |
+2. Setup your credentials |
|
| 80 |
+ |
|
| 81 |
+ By default the Git Server will allow users or service accounts that can create pods in |
|
| 82 |
+ the project namespace to create and push code to the Git Server. The easiest way to |
|
| 83 |
+ provide credentials to the Git Server is by using a custom credential helper that will |
|
| 84 |
+ send your OpenShift token by default to the server. |
|
| 85 |
+ ```sh |
|
| 86 |
+ $ git config --global credential.http://gitserver-myproject.infra.openshift.com.helper \ |
|
| 87 |
+ '!f() { echo "username=$(oc whoami)"; echo "password=$(oc whoami -t)"; }; f'
|
|
| 88 |
+ ``` |
|
| 89 |
+ |
|
| 90 |
+ **NOTE:** the config key is `credential.[git server URL].helper` |
|
| 91 |
+ |
|
| 92 |
+3. Push a repository to your git server |
|
| 93 |
+ |
|
| 94 |
+ In an existing repository, add a remote that points to the git server and push to it |
|
| 95 |
+ |
|
| 96 |
+ ``` |
|
| 97 |
+ # clone a public repository |
|
| 98 |
+ $ git clone https://github.com/openshift/ruby-hello-world.git |
|
| 99 |
+ |
|
| 100 |
+ # add a remote for your git server |
|
| 101 |
+ $ cd ruby-hello-world |
|
| 102 |
+ $ git remote add openshift http://git-myproject.infra.openshift.com/ruby-hello-world.git |
|
| 103 |
+ |
|
| 104 |
+ # push the code to the git server |
|
| 105 |
+ $ git push openshift master |
|
| 106 |
+ ``` |
|
| 107 |
+ |
|
| 108 |
+ **NOTE:** the ruby-hello-world.git repository does not exist before running these commands. |
|
| 109 |
+ By pushing to it, you are creating it in the Git Server. |
|
| 110 |
+ |
|
| 111 |
+ On push the git server will invoke new-app on the code and create artifacts for it in |
|
| 112 |
+ OpenShift. |
|
| 113 |
+ |
|
| 114 |
+ |
|
| 115 |
+### Secure the Git Server |
|
| 116 |
+ |
|
| 117 |
+Beyond demo uses, it is recommended that communication with the Git server be encrypted with the TLS |
|
| 118 |
+protocol to avoid transmission of source in plain text. |
|
| 119 |
+ |
|
| 120 |
+1. Modify your route to use edge termination: |
|
| 121 |
+ |
|
| 122 |
+ ```sh |
|
| 123 |
+ $ oc edit route git |
|
| 124 |
+ ``` |
|
| 125 |
+ |
|
| 126 |
+ Add tls -> termination -> edge to the route specification: |
|
| 127 |
+ |
|
| 128 |
+ ```yaml |
|
| 129 |
+ apiVersion: v1 |
|
| 130 |
+ kind: Route |
|
| 131 |
+ metadata: |
|
| 132 |
+ name: gitserver |
|
| 133 |
+ spec: |
|
| 134 |
+ host: gitserver-myproject.infra.openshift.com |
|
| 135 |
+ tls: |
|
| 136 |
+ termination: edge |
|
| 137 |
+ to: |
|
| 138 |
+ kind: Service |
|
| 139 |
+ name: gitserver |
|
| 140 |
+ ``` |
|
| 141 |
+ |
|
| 142 |
+2. If using a private certificate authority, configure your git client to use the private ca.crt file: |
|
| 143 |
+ |
|
| 144 |
+ ```sh |
|
| 145 |
+ $ git config --global http.https://gitserver-myproject.infra.openshift.com.sslCAInfo /path/to/ca.crt |
|
| 146 |
+ ``` |
|
| 147 |
+ |
|
| 148 |
+ where the key is http.[git server URL].sslCAInfo |
|
| 149 |
+ |
|
| 150 |
+3. Disable anonymous cloning. By default the gitserver will allow anonymous cloning to make it easier to |
|
| 151 |
+ run builds without having to specify a secret. You can disable this by setting the `ALLOW_ANON_GIT_PULL` |
|
| 152 |
+ environment variable to `false`. |
|
| 153 |
+ |
|
| 154 |
+ ```sh |
|
| 155 |
+ $ oc set env dc/git ALLOW_ANON_GIT_PULL=false |
|
| 156 |
+ ``` |
|
| 157 |
+ |
|
| 158 |
+ **NOTE:** changing environment variables on the git server will cause a redeploy of the git server. If using |
|
| 159 |
+ the default ephemeral storage for it, all repositories that have been pushed previously will be wiped out. |
|
| 160 |
+ They will need to be pushed to the server again to restore. |
|
| 161 |
+ |
|
| 162 |
+Authentication |
|
| 163 |
+-------------- |
|
| 164 |
+ |
|
| 165 |
+By default, the gitserver will authenticate using OpenShift user or service account credentials. For a user, |
|
| 166 |
+the credentials are the user name, and the user's token (from `oc whoami -t`). For a service account, the user |
|
| 167 |
+name is the service account name and the password is the service account token. The token can |
|
| 168 |
+be one of the 2 tokens created with the service account and stored in the service account secrets. These can |
|
| 169 |
+be obtained by looking at the secrets that correspond to the service account (`oc get secrets`) and displaying |
|
| 170 |
+the token in one of them: `oc describe secret NAME`. |
|
| 171 |
+ |
|
| 172 |
+ |
|
| 173 |
+Authorization |
|
| 174 |
+------------- |
|
| 175 |
+ |
|
| 176 |
+Users or service accounts must be able to read pods in the current namespace in order to fetch repositories from |
|
| 177 |
+the Git Server. Specifying ALLOW_ANON_GIT_PULL=true as an environment variable for the Git Server will allow anyone |
|
| 178 |
+to fetch/clone content from the Git Server. To create/push content, users or service accounts must have the right |
|
| 179 |
+to create pods in the namespace. |
|
| 180 |
+ |
|
| 181 |
+ |
|
| 182 |
+Automatically Cloning Public Repositories |
|
| 183 |
+----------------------------------------- |
|
| 184 |
+ |
|
| 185 |
+The Git Server can automatically clone a set of repositories on startup if it is going to be used for mirroring |
|
| 186 |
+purposes. Repositories to be cloned can be specified using a set of environment variables that match |
|
| 187 |
+`GIT_INITIAL_CLONE_[name]` where [name] must be unique. The value of the variable must be a URL to the remote |
|
| 188 |
+repository to clone and an optional name for the clone. |
|
| 189 |
+ |
|
| 190 |
+The following command will add an environment variable to clone the openshift/ruby-hello-world repository and give |
|
| 191 |
+it a name of `helloworld` inside the Git Server. |
|
| 192 |
+ |
|
| 193 |
+```sh |
|
| 194 |
+$ oc set env dc/gitserver GIT_INITIAL_CLONE_1="https://github.com/openshift/ruby-hello-world.git;helloworld" |
|
| 195 |
+``` |
|
| 196 |
+ |
|
| 197 |
+Automatically Starting Builds |
|
| 198 |
+----------------------------- |
|
| 199 |
+ |
|
| 200 |
+By default, whenever the git server receives a commit, it will look for a BuildConfig in the same namespace as the |
|
| 201 |
+git server and the same name as the repository where the commit is being pushed. If it finds a BuildConfig with |
|
| 202 |
+the same name, it will start a build for that BuildConfig. Alternatively, an annotation may be added to a |
|
| 203 |
+BuildConfig to explicitly link it to a repository on the git server: |
|
| 204 |
+ |
|
| 205 |
+```yaml |
|
| 206 |
+apiVersion: v1 |
|
| 207 |
+kind: BuildConfig |
|
| 208 |
+metadata: |
|
| 209 |
+ annotations: |
|
| 210 |
+ openshift.io/git-repository: myrepo |
|
| 211 |
+``` |
|
| 212 |
+ |
|
| 213 |
+**NOTE**: A build will be started for the BuildConfig matching the name of the repository and for any BuildConfig |
|
| 214 |
+that has an annotation pointing to the source repository. If there is a BuildConfig that has a matching name but |
|
| 215 |
+has an annotation pointing to a different repository, a build will not be invoked for it. |
| ... | ... |
@@ -2,28 +2,28 @@ apiVersion: v1 |
| 2 | 2 |
kind: List |
| 3 | 3 |
items: |
| 4 | 4 |
|
| 5 |
-# The gitserver is deployed as a singleton pod and uses a very small amount |
|
| 5 |
+# The git server is deployed as a singleton pod and uses a very small amount |
|
| 6 | 6 |
# of resources. It can host or transiently serve Git repositories, as well |
| 7 | 7 |
# as automatically integrate with builds in a namespace. |
| 8 | 8 |
- apiVersion: v1 |
| 9 | 9 |
kind: DeploymentConfig |
| 10 | 10 |
metadata: |
| 11 |
- name: gitserver |
|
| 11 |
+ name: git |
|
| 12 | 12 |
labels: |
| 13 |
- app: gitserver |
|
| 13 |
+ app: git |
|
| 14 | 14 |
spec: |
| 15 |
- replicas: 1 # the gitserver is not HA and should not be scaled past 1 |
|
| 15 |
+ replicas: 1 # the git server is not HA and should not be scaled past 1 |
|
| 16 | 16 |
selector: |
| 17 |
- run-container: gitserver |
|
| 17 |
+ run-container: git |
|
| 18 | 18 |
template: |
| 19 | 19 |
metadata: |
| 20 | 20 |
labels: |
| 21 |
- run-container: gitserver |
|
| 21 |
+ run-container: git |
|
| 22 | 22 |
spec: |
| 23 |
- serviceAccountName: gitserver |
|
| 23 |
+ serviceAccountName: git |
|
| 24 | 24 |
containers: |
| 25 |
- - name: gitserver |
|
| 26 |
- image: openshift/origin-gitserver |
|
| 25 |
+ - name: git |
|
| 26 |
+ image: openshift/origin-gitserver:latest |
|
| 27 | 27 |
ports: |
| 28 | 28 |
- containerPort: 8080 |
| 29 | 29 |
|
| ... | ... |
@@ -51,7 +51,13 @@ items: |
| 51 | 51 |
# stored in this app. |
| 52 | 52 |
# TOOD: support HTTPS |
| 53 | 53 |
- name: PUBLIC_URL |
| 54 |
- value: http://gitserver.$(POD_NAMESPACE).svc.cluster.local:8080 |
|
| 54 |
+ value: http://git.$(POD_NAMESPACE).svc.cluster.local:8080 |
|
| 55 |
+ # If INTERNAL_URL is specified, then it's used to point |
|
| 56 |
+ # BuildConfigs to the internal service address of the git |
|
| 57 |
+ # server |
|
| 58 |
+ - name: INTERNAL_URL |
|
| 59 |
+ value: http://git:8080 |
|
| 60 |
+ |
|
| 55 | 61 |
# The directory to store Git repositories in. If not backed |
| 56 | 62 |
# by a persistent volume, repositories will be lost when |
| 57 | 63 |
# deployments occur. Use INITIAL_GIT_CLONE and AUTOLINK_* |
| ... | ... |
@@ -62,26 +68,39 @@ items: |
| 62 | 62 |
# The directory to use as the default hook directory for any |
| 63 | 63 |
# cloned or autolinked directories. |
| 64 | 64 |
- name: HOOK_PATH |
| 65 |
- # value: /var/lib/git-hooks |
|
| 65 |
+ value: /var/lib/git-hooks |
|
| 66 |
+ |
|
| 67 |
+ # If 'true' new-app will be invoked on push for repositories |
|
| 68 |
+ # for which a matching BuildConfig is not found. |
|
| 69 |
+ - name: GENERATE_ARTIFACTS |
|
| 70 |
+ value: "true" |
|
| 71 |
+ |
|
| 72 |
+ # The script to use for custom language detection on a |
|
| 73 |
+ # repository. See hooks/detect-language for an example. |
|
| 74 |
+ # To use new-app's default detection, leave this variable |
|
| 75 |
+ # blank. |
|
| 76 |
+ - name: DETECTION_SCRIPT |
|
| 77 |
+ # value: detect-language |
|
| 66 | 78 |
|
| 67 | 79 |
# Authentication and authorization |
| 68 | 80 |
|
| 69 |
- # If 'yes', clients may push to the server with git push. |
|
| 81 |
+ # If 'true', clients may push to the server with git push. |
|
| 70 | 82 |
- name: ALLOW_GIT_PUSH |
| 71 |
- value: "yes" |
|
| 72 |
- # If 'yes', clients may set hooks via the API. However, unless |
|
| 83 |
+ value: "true" |
|
| 84 |
+ # If 'true', clients may set hooks via the API. However, unless |
|
| 73 | 85 |
# the Git home is backed by a persistent volume, any deployment |
| 74 | 86 |
# will result in the hooks being lost. |
| 75 | 87 |
- name: ALLOW_GIT_HOOKS |
| 76 |
- value: "yes" |
|
| 77 |
- # If 'yes', clients can create new git repositories on demand |
|
| 88 |
+ value: "true" |
|
| 89 |
+ # If 'true', clients can create new git repositories on demand |
|
| 78 | 90 |
# by pushing. If the data on disk is not backed by a persistent |
| 79 | 91 |
# volume, the Git repo will be deleted if the deployment is |
| 80 | 92 |
# updated. |
| 81 | 93 |
- name: ALLOW_LAZY_CREATE |
| 82 |
- value: "yes" |
|
| 83 |
- # If 'yes', clients can pull without being authenticated. |
|
| 94 |
+ value: "true" |
|
| 95 |
+ # If 'true', clients can pull without being authenticated. |
|
| 84 | 96 |
- name: ALLOW_ANON_GIT_PULL |
| 97 |
+ value: "true" |
|
| 85 | 98 |
|
| 86 | 99 |
# Provides the path to a kubeconfig file in the image that |
| 87 | 100 |
# should be used to authorize against the server. The value |
| ... | ... |
@@ -102,7 +121,7 @@ items: |
| 102 | 102 |
|
| 103 | 103 |
# Autolinking: |
| 104 | 104 |
# |
| 105 |
- # The gitserver can automatically clone Git repositories |
|
| 105 |
+ # The git server can automatically clone Git repositories |
|
| 106 | 106 |
# associated with a build config and replace the URL with |
| 107 | 107 |
# a link to the repo on PUBLIC_URL. The default post-receive |
| 108 | 108 |
# hook on the cloned repo will then trigger a build. You |
| ... | ... |
@@ -110,8 +129,7 @@ items: |
| 110 | 110 |
# To autolink, the account the pod runs under must have 'edit' |
| 111 | 111 |
# on the AUTOLINK_NAMESPACE: |
| 112 | 112 |
# |
| 113 |
- # oc policy add-role-to-user \ |
|
| 114 |
- # system:serviceaccount:${namespace}:gitserver edit
|
|
| 113 |
+ # oc policy add-role-to-user -z git edit |
|
| 115 | 114 |
# |
| 116 | 115 |
# Links are checked every time the pod starts. |
| 117 | 116 |
|
| ... | ... |
@@ -132,12 +150,6 @@ items: |
| 132 | 132 |
# image for examples. |
| 133 | 133 |
- name: AUTOLINK_HOOK |
| 134 | 134 |
|
| 135 |
- # The master service host is not signed with the service IP |
|
| 136 |
- # so we override with the consistent DNS name. Required for |
|
| 137 |
- # connections to the server. |
|
| 138 |
- - name: KUBERNETES_SERVICE_HOST |
|
| 139 |
- value: kubernetes.default |
|
| 140 |
- |
|
| 141 | 135 |
volumeMounts: |
| 142 | 136 |
- mountPath: /var/lib/git/ |
| 143 | 137 |
name: git |
| ... | ... |
@@ -147,25 +159,36 @@ items: |
| 147 | 147 |
triggers: |
| 148 | 148 |
- type: ConfigChange |
| 149 | 149 |
|
| 150 |
-# The gitserver service is required for DNS resolution |
|
| 150 |
+# The git server service is required for DNS resolution |
|
| 151 | 151 |
- apiVersion: v1 |
| 152 | 152 |
kind: Service |
| 153 | 153 |
metadata: |
| 154 |
- name: gitserver |
|
| 154 |
+ name: git |
|
| 155 | 155 |
labels: |
| 156 |
- app: gitserver |
|
| 156 |
+ app: git |
|
| 157 | 157 |
spec: |
| 158 | 158 |
ports: |
| 159 | 159 |
- port: 8080 |
| 160 | 160 |
targetPort: 8080 |
| 161 | 161 |
selector: |
| 162 |
- run-container: gitserver |
|
| 162 |
+ run-container: git |
|
| 163 | 163 |
|
| 164 |
-# The service account for the gitserver must be granted the edit role if |
|
| 165 |
-# you wish to use autolinking. |
|
| 164 |
+# The service account for the git server must be granted the view role to |
|
| 165 |
+# automatically start builds, edit role to create objects and autolink |
|
| 166 | 166 |
- apiVersion: v1 |
| 167 | 167 |
kind: ServiceAccount |
| 168 | 168 |
metadata: |
| 169 |
- name: gitserver |
|
| 169 |
+ name: git |
|
| 170 | 170 |
labels: |
| 171 |
- app: gitserver |
|
| 171 |
+ app: git |
|
| 172 |
+ |
|
| 173 |
+# Default route for git service |
|
| 174 |
+- apiVersion: v1 |
|
| 175 |
+ kind: Route |
|
| 176 |
+ metadata: |
|
| 177 |
+ labels: |
|
| 178 |
+ app: git |
|
| 179 |
+ name: git |
|
| 180 |
+ spec: |
|
| 181 |
+ to: |
|
| 182 |
+ name: git |
| ... | ... |
@@ -20,13 +20,13 @@ function key {
|
| 20 | 20 |
|
| 21 | 21 |
prefix=${PREFIX:-openshift/}
|
| 22 | 22 |
|
| 23 |
-if has Gemfile; then |
|
| 23 |
+if has Gemfile Rakefile config.ru; then |
|
| 24 | 24 |
echo "${prefix}ruby"
|
| 25 | 25 |
exit 0 |
| 26 | 26 |
fi |
| 27 | 27 |
|
| 28 |
-if has requirements.txt; then |
|
| 29 |
- echo "${prefix}python"
|
|
| 28 |
+if has pom.xml; then |
|
| 29 |
+ echo "${prefix}wildfly"
|
|
| 30 | 30 |
exit 0 |
| 31 | 31 |
fi |
| 32 | 32 |
|
| ... | ... |
@@ -35,14 +35,19 @@ if has package.json app.json; then |
| 35 | 35 |
exit 0 |
| 36 | 36 |
fi |
| 37 | 37 |
|
| 38 |
-if has '*.go'; then |
|
| 39 |
- echo "${prefix}golang"
|
|
| 38 |
+if has index.php composer.json; then |
|
| 39 |
+ echo "${prefix}php"
|
|
| 40 | 40 |
exit 0 |
| 41 | 41 |
fi |
| 42 | 42 |
|
| 43 |
-if has index.php; then |
|
| 44 |
- echo "${prefix}php"
|
|
| 43 |
+if has requirements.txt setup.py; then |
|
| 44 |
+ echo "${prefix}python"
|
|
| 45 |
+ exit 0 |
|
| 46 |
+fi |
|
| 47 |
+ |
|
| 48 |
+if has index.pl cpanfile; then |
|
| 49 |
+ echo "${prefix}perl"
|
|
| 45 | 50 |
exit 0 |
| 46 | 51 |
fi |
| 47 | 52 |
|
| 48 |
-exit 1 |
|
| 49 | 53 |
\ No newline at end of file |
| 54 |
+exit 1 |
| ... | ... |
@@ -7,48 +7,77 @@ set -o pipefail |
| 7 | 7 |
function key {
|
| 8 | 8 |
git config --local --get "${1}"
|
| 9 | 9 |
} |
| 10 |
+ |
|
| 10 | 11 |
function addkey {
|
| 11 | 12 |
git config --local --add "${1}" "${2}"
|
| 12 | 13 |
} |
| 13 | 14 |
|
| 14 | 15 |
function detect {
|
| 15 |
- if detected=$(key openshift.io.detect); then |
|
| 16 |
- exit 0 |
|
| 17 |
- fi |
|
| 18 |
- if ! url=$(key gitserver.self.url); then |
|
| 19 |
- echo "detect: no self url set" |
|
| 20 |
- exit 0 |
|
| 16 |
+ local repoURL="$1" |
|
| 17 |
+ local repoName="$2" |
|
| 18 |
+ local detectionScript=${DETECTION_SCRIPT:-}
|
|
| 19 |
+ # The purpose of using a custom detection script is that users can customize the |
|
| 20 |
+ # 'detect-language' script to return the image that's appropriate for their needs. |
|
| 21 |
+ # It is possible to just have new-app do code detection. In that case, just set |
|
| 22 |
+ # the DETECTION_SCRIPT variable to an empty string. |
|
| 23 |
+ if [[ -z $detectionScript ]]; then |
|
| 24 |
+ oc new-app "${repoURL}"
|
|
| 25 |
+ else |
|
| 26 |
+ if ! lang=$($(dirname $0)/${detectionScript}); then
|
|
| 27 |
+ return |
|
| 28 |
+ fi |
|
| 29 |
+ echo "detect: found language ${lang} for ${repoName}"
|
|
| 30 |
+ oc new-app "${lang}~${repoURL}"
|
|
| 21 | 31 |
fi |
| 32 |
+ # TODO: when a command to set a secret is available, |
|
| 33 |
+ # set an optional secret on the resulting build configuration |
|
| 34 |
+} |
|
| 22 | 35 |
|
| 23 |
- # TODO: make it easier to find the build config name created |
|
| 24 |
- # by oc new-app |
|
| 25 |
- name=$(basename "${url}")
|
|
| 26 |
- name="${name%.*}"
|
|
| 36 |
+# If the 'oc' command is not found, exit |
|
| 37 |
+if ! oc=$(which oc); then |
|
| 38 |
+ echo "detect: oc is not installed" |
|
| 39 |
+ exit 0 |
|
| 40 |
+fi |
|
| 27 | 41 |
|
| 28 |
- if ! lang=$($(dirname $0)/detect-language); then |
|
| 29 |
- exit 0 |
|
| 30 |
- fi |
|
| 31 |
- echo "detect: found language ${lang} for ${name}"
|
|
| 42 |
+# If the current repository has no self.url, exit |
|
| 43 |
+if ! url=$(key gitserver.self.url); then |
|
| 44 |
+ echo "post-receive: no self url set" |
|
| 45 |
+ exit 0 |
|
| 46 |
+fi |
|
| 32 | 47 |
|
| 33 |
- if ! oc=$(which oc); then |
|
| 34 |
- echo "detect: oc is not installed" |
|
| 35 |
- addkey openshift.io.detect 1 |
|
| 36 |
- exit 0 |
|
| 37 |
- fi |
|
| 38 |
- oc new-app "${lang}~${url}"
|
|
| 39 |
- if webhook=$(oc start-build --list-webhooks="generic" "${name}" | head -n 1); then
|
|
| 40 |
- addkey openshift.io.webhook "${webhook}"
|
|
| 41 |
- fi |
|
| 42 |
- addkey openshift.io.detect 1 |
|
| 43 |
-} |
|
| 48 |
+# Save received commits to a temporary file |
|
| 49 |
+commits=$(mktemp) |
|
| 50 |
+cat > ${commits}
|
|
| 44 | 51 |
|
| 45 |
-cat > /tmp/postreceived |
|
| 52 |
+# Extract the name of the repository from the URL |
|
| 53 |
+name=$(basename "${url}")
|
|
| 54 |
+name="${name%.*}"
|
|
| 46 | 55 |
|
| 47 |
-detect |
|
| 56 |
+foundbc=false |
|
| 57 |
+# Loop through build configurations that match this git repository |
|
| 58 |
+while read bc ref |
|
| 59 |
+do |
|
| 60 |
+ foundbc=true |
|
| 61 |
+ # If a generic webhook exists on the build config, determine if one of the received |
|
| 62 |
+ # commits affects the reference in the build configuration |
|
| 63 |
+ if webhook=$(oc start-build --list-webhooks="generic" "${bc}" | head -n 1); then
|
|
| 64 |
+ # Loop through the commits received by the hook. If the build configuration's git ref is an |
|
| 65 |
+ # ancestor for the received commit, then start a new build for it. |
|
| 66 |
+ while read old_commit new_commit ref_name |
|
| 67 |
+ do |
|
| 68 |
+ if $(git merge-base --is-ancestor "${ref}" "${new_commit}"); then
|
|
| 69 |
+ oc start-build --from-webhook="${webhook}" && echo "build: started on build configuration '${bc}'"
|
|
| 70 |
+ break |
|
| 71 |
+ fi |
|
| 72 |
+ done < "${commits}"
|
|
| 73 |
+ fi |
|
| 74 |
+done < <(gitrepo-buildconfigs "${name}")
|
|
| 75 |
+ |
|
| 76 |
+if $foundbc; then |
|
| 77 |
+ exit 0 |
|
| 78 |
+fi |
|
| 48 | 79 |
|
| 49 |
-if webhook=$(key openshift.io.webhook); then |
|
| 50 |
- # TODO: print output from the server about the hook status |
|
| 51 |
- oc start-build --from-webhook="${webhook}"
|
|
| 52 |
- # TODO: follow logs |
|
| 53 |
- echo "build: started" |
|
| 80 |
+generate_artifacts=${GENERATE_ARTIFACTS:-}
|
|
| 81 |
+if [ "${generate_artifacts}" == "true" ]; then
|
|
| 82 |
+ detect "$url" "$name" |
|
| 54 | 83 |
fi |
| 55 | 84 |
deleted file mode 100644 |
| ... | ... |
@@ -1,23 +0,0 @@ |
| 1 |
-package main |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "log" |
|
| 6 |
- "os" |
|
| 7 |
- |
|
| 8 |
- "github.com/openshift/origin/pkg/gitserver" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-func main() {
|
|
| 12 |
- if len(os.Args) != 1 {
|
|
| 13 |
- fmt.Printf(`git-server - Expose Git repositories to the network |
|
| 14 |
- |
|
| 15 |
-%[1]s`, gitserver.EnvironmentHelp) |
|
| 16 |
- os.Exit(0) |
|
| 17 |
- } |
|
| 18 |
- config, err := gitserver.NewEnviromentConfig() |
|
| 19 |
- if err != nil {
|
|
| 20 |
- log.Fatal(err) |
|
| 21 |
- } |
|
| 22 |
- log.Fatal(gitserver.Start(config)) |
|
| 23 |
-} |
| ... | ... |
@@ -1,9 +1,12 @@ |
| 1 | 1 |
package gitserver |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "flag" |
|
| 4 | 5 |
"fmt" |
| 6 |
+ "io" |
|
| 5 | 7 |
"log" |
| 6 | 8 |
"net/url" |
| 9 |
+ "os" |
|
| 7 | 10 |
|
| 8 | 11 |
"github.com/spf13/cobra" |
| 9 | 12 |
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
| ... | ... |
@@ -20,6 +23,30 @@ and automatic creation of applications on push. |
| 20 | 20 |
|
| 21 | 21 |
%[1]s |
| 22 | 22 |
` |
| 23 |
+const LogLevelEnv = "LOGLEVEL" |
|
| 24 |
+const repositoryBuildConfigsDesc = ` |
|
| 25 |
+Retrieve build configs for a gitserver repository |
|
| 26 |
+ |
|
| 27 |
+This command lists build configurations in the current namespace that correspond to a given git repository. |
|
| 28 |
+` |
|
| 29 |
+ |
|
| 30 |
+// CommandFor returns the appropriate command for this base name, |
|
| 31 |
+// or the global OpenShift command |
|
| 32 |
+func CommandFor(basename string) *cobra.Command {
|
|
| 33 |
+ var cmd *cobra.Command |
|
| 34 |
+ |
|
| 35 |
+ out := os.Stdout |
|
| 36 |
+ |
|
| 37 |
+ setLogLevel() |
|
| 38 |
+ |
|
| 39 |
+ switch basename {
|
|
| 40 |
+ case "gitrepo-buildconfigs": |
|
| 41 |
+ cmd = NewCommandRepositoryBuildConfigs(basename, out) |
|
| 42 |
+ default: |
|
| 43 |
+ cmd = NewCommandGitServer("gitserver")
|
|
| 44 |
+ } |
|
| 45 |
+ return cmd |
|
| 46 |
+} |
|
| 23 | 47 |
|
| 24 | 48 |
// NewCommandGitServer launches a Git server |
| 25 | 49 |
func NewCommandGitServer(name string) *cobra.Command {
|
| ... | ... |
@@ -59,3 +86,30 @@ func RunGitServer() error {
|
| 59 | 59 |
} |
| 60 | 60 |
return gitserver.Start(config) |
| 61 | 61 |
} |
| 62 |
+ |
|
| 63 |
+func NewCommandRepositoryBuildConfigs(name string, out io.Writer) *cobra.Command {
|
|
| 64 |
+ cmd := &cobra.Command{
|
|
| 65 |
+ Use: fmt.Sprintf("%s REPOSITORY_NAME", name),
|
|
| 66 |
+ Short: "Retrieve build configs for a gitserver repository", |
|
| 67 |
+ Long: repositoryBuildConfigsDesc, |
|
| 68 |
+ Run: func(c *cobra.Command, args []string) {
|
|
| 69 |
+ if len(args) != 1 {
|
|
| 70 |
+ err := cmdutil.UsageError(c, "This command takes a single argument - the name of the repository") |
|
| 71 |
+ cmdutil.CheckErr(err) |
|
| 72 |
+ } |
|
| 73 |
+ repoName := args[0] |
|
| 74 |
+ err := gitserver.GetRepositoryBuildConfigs(repoName, out) |
|
| 75 |
+ cmdutil.CheckErr(err) |
|
| 76 |
+ }, |
|
| 77 |
+ } |
|
| 78 |
+ return cmd |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func setLogLevel() {
|
|
| 82 |
+ logLevel := os.Getenv(LogLevelEnv) |
|
| 83 |
+ if len(logLevel) > 0 {
|
|
| 84 |
+ if flag.CommandLine.Lookup("v") != nil {
|
|
| 85 |
+ flag.CommandLine.Set("v", logLevel)
|
|
| 86 |
+ } |
|
| 87 |
+ } |
|
| 88 |
+} |
| 62 | 89 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,68 @@ |
| 0 |
+package gitserver |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "io" |
|
| 5 |
+ "os" |
|
| 6 |
+ |
|
| 7 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 8 |
+ "k8s.io/kubernetes/pkg/client/restclient" |
|
| 9 |
+ |
|
| 10 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
| 11 |
+ "github.com/openshift/origin/pkg/client" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+const gitRepositoryAnnotationKey = "openshift.io/git-repository" |
|
| 15 |
+ |
|
| 16 |
+func GetRepositoryBuildConfigs(name string, out io.Writer) error {
|
|
| 17 |
+ client, err := getClient() |
|
| 18 |
+ if err != nil {
|
|
| 19 |
+ return err |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ ns := os.Getenv("POD_NAMESPACE")
|
|
| 23 |
+ buildConfigList, err := client.BuildConfigs(ns).List(kapi.ListOptions{})
|
|
| 24 |
+ if err != nil {
|
|
| 25 |
+ return err |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ matchingBuildConfigs := []*buildapi.BuildConfig{}
|
|
| 29 |
+ |
|
| 30 |
+ for _, bc := range buildConfigList.Items {
|
|
| 31 |
+ repoAnnotation, hasAnnotation := bc.Annotations[gitRepositoryAnnotationKey] |
|
| 32 |
+ if hasAnnotation {
|
|
| 33 |
+ if repoAnnotation == name {
|
|
| 34 |
+ matchingBuildConfigs = append(matchingBuildConfigs, &bc) |
|
| 35 |
+ } |
|
| 36 |
+ continue |
|
| 37 |
+ } |
|
| 38 |
+ if bc.Name == name {
|
|
| 39 |
+ matchingBuildConfigs = append(matchingBuildConfigs, &bc) |
|
| 40 |
+ } |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ for _, bc := range matchingBuildConfigs {
|
|
| 44 |
+ var ref string |
|
| 45 |
+ if bc.Spec.Source.Git != nil {
|
|
| 46 |
+ ref = bc.Spec.Source.Git.Ref |
|
| 47 |
+ } |
|
| 48 |
+ if ref == "" {
|
|
| 49 |
+ ref = "master" |
|
| 50 |
+ } |
|
| 51 |
+ fmt.Fprintf(out, "%s %s\n", bc.Name, ref) |
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ return nil |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+func getClient() (client.Interface, error) {
|
|
| 58 |
+ clientConfig, err := restclient.InClusterConfig() |
|
| 59 |
+ if err != nil {
|
|
| 60 |
+ return nil, fmt.Errorf("failed to get client config: %v", err)
|
|
| 61 |
+ } |
|
| 62 |
+ osClient, err := client.New(clientConfig) |
|
| 63 |
+ if err != nil {
|
|
| 64 |
+ return nil, fmt.Errorf("error obtaining OpenShift client: %v", err)
|
|
| 65 |
+ } |
|
| 66 |
+ return osClient, nil |
|
| 67 |
+} |
| ... | ... |
@@ -5,7 +5,6 @@ package gitserver |
| 5 | 5 |
|
| 6 | 6 |
import ( |
| 7 | 7 |
"fmt" |
| 8 |
- "log" |
|
| 9 | 8 |
"net/http" |
| 10 | 9 |
"net/url" |
| 11 | 10 |
"os" |
| ... | ... |
@@ -16,6 +15,7 @@ import ( |
| 16 | 16 |
|
| 17 | 17 |
"github.com/AaronO/go-git-http" |
| 18 | 18 |
"github.com/AaronO/go-git-http/auth" |
| 19 |
+ "github.com/golang/glog" |
|
| 19 | 20 |
"github.com/prometheus/client_golang/prometheus" |
| 20 | 21 |
|
| 21 | 22 |
kapi "k8s.io/kubernetes/pkg/api" |
| ... | ... |
@@ -35,31 +35,45 @@ GIT_HOME |
| 35 | 35 |
directory containing Git repositories; defaults to current directory |
| 36 | 36 |
PUBLIC_URL |
| 37 | 37 |
the url of this server for constructing URLs that point to this repository |
| 38 |
+INTERNAL_URL |
|
| 39 |
+ the url of this server that can be used internally by build configs in the cluster |
|
| 38 | 40 |
GIT_PATH |
| 39 | 41 |
path to Git binary; defaults to location of 'git' in PATH |
| 40 | 42 |
HOOK_PATH |
| 41 | 43 |
path to a directory containing hooks for all repositories; if not set no global hooks will be used |
| 42 | 44 |
ALLOW_GIT_PUSH |
| 43 |
- if 'no', pushes will be not be accepted; defaults to true |
|
| 45 |
+ if 'false', pushes will be not be accepted; defaults to true |
|
| 44 | 46 |
ALLOW_ANON_GIT_PULL |
| 45 |
- if 'yes', pulls may be made without authorization; defaults to false |
|
| 47 |
+ if 'true', pulls may be made without authorization; defaults to false |
|
| 46 | 48 |
ALLOW_GIT_HOOKS |
| 47 |
- if 'no', hooks cannot be read or set; defaults to true |
|
| 49 |
+ if 'false', hooks cannot be read or set; defaults to true |
|
| 48 | 50 |
ALLOW_LAZY_CREATE |
| 49 |
- if 'no', repositories will not automatically be initialized on push; defaults to true |
|
| 51 |
+ if 'false', repositories will not automatically be initialized on push; defaults to true |
|
| 50 | 52 |
REQUIRE_GIT_AUTH |
| 51 | 53 |
a user/password combination required to access the repo of the form "<user>:<password>"; defaults to none |
| 52 | 54 |
REQUIRE_SERVER_AUTH |
| 53 |
- a URL to an OpenShift server for verifying authorization credentials provided by a user. Requires |
|
| 54 |
- AUTOLINK_NAMESPACE to be set (the namespace that authorization will be checked in). Users must have |
|
| 55 |
- 'get' on 'pods' to pull (be a viewer) and 'create' on 'pods' to push (be an editor) |
|
| 55 |
+ a URL to an OpenShift server for verifying authorization credentials provided by a user. Requires |
|
| 56 |
+ AUTOLINK_NAMESPACE to be set (the namespace that authorization will be checked in). Users must have |
|
| 57 |
+ 'get' on 'pods' to pull (be a viewer) and 'create' on 'pods' to push (be an editor) |
|
| 56 | 58 |
GIT_FORCE_CLEAN |
| 57 |
- if 'yes', any initial repository directories will be deleted prior to start; defaults to no |
|
| 59 |
+ if 'true', any initial repository directories will be deleted prior to start; defaults to 'false' |
|
| 58 | 60 |
WARNING: this is destructive and you will lose any data you have already pushed |
| 59 | 61 |
GIT_INITIAL_CLONE_*=<url>[;<name>] |
| 60 | 62 |
each environment variable in this pattern will be cloned when the process starts; failures will be logged |
| 61 | 63 |
<name> must be [A-Z0-9_\-\.], the cloned directory name will be lowercased. If the name is invalid the |
| 62 | 64 |
process will halt. If the repository already exists on disk, it will be updated from the remote. |
| 65 |
+AUTOLINK_KUBECONFIG |
|
| 66 |
+ The location to read auth configuration from for autolinking. |
|
| 67 |
+ If '-', use the service account token to link. The account |
|
| 68 |
+ represented by this config must have the edit role on the |
|
| 69 |
+ namespace. |
|
| 70 |
+AUTOLINK_NAMESPACE |
|
| 71 |
+ The namespace to autolink |
|
| 72 |
+AUTOLINK_HOOK |
|
| 73 |
+ The path to a script in the image to use as the default |
|
| 74 |
+ post-receive hook - only set during link, so has no effect |
|
| 75 |
+ on cloned repositories. See the "hooks" directory in the |
|
| 76 |
+ image for examples. |
|
| 63 | 77 |
` |
| 64 | 78 |
) |
| 65 | 79 |
|
| ... | ... |
@@ -82,9 +96,10 @@ func init() {
|
| 82 | 82 |
|
| 83 | 83 |
// Config represents the configuration to use for running the server |
| 84 | 84 |
type Config struct {
|
| 85 |
- Home string |
|
| 86 |
- GitBinary string |
|
| 87 |
- URL *url.URL |
|
| 85 |
+ Home string |
|
| 86 |
+ GitBinary string |
|
| 87 |
+ URL *url.URL |
|
| 88 |
+ InternalURL *url.URL |
|
| 88 | 89 |
|
| 89 | 90 |
AllowHooks bool |
| 90 | 91 |
AllowPush bool |
| ... | ... |
@@ -152,6 +167,14 @@ func NewEnviromentConfig() (*Config, error) {
|
| 152 | 152 |
config.URL = valid |
| 153 | 153 |
} |
| 154 | 154 |
|
| 155 |
+ if internalURL := os.Getenv("INTERNAL_URL"); len(internalURL) > 0 {
|
|
| 156 |
+ valid, err := url.Parse(internalURL) |
|
| 157 |
+ if err != nil {
|
|
| 158 |
+ return nil, fmt.Errorf("INTERNAL_URL must be a valid URL: %v", err)
|
|
| 159 |
+ } |
|
| 160 |
+ config.InternalURL = valid |
|
| 161 |
+ } |
|
| 162 |
+ |
|
| 155 | 163 |
gitpath := os.Getenv("GIT_PATH")
|
| 156 | 164 |
if len(gitpath) == 0 {
|
| 157 | 165 |
path, err := exec.LookPath("git")
|
| ... | ... |
@@ -162,9 +185,9 @@ func NewEnviromentConfig() (*Config, error) {
|
| 162 | 162 |
} |
| 163 | 163 |
config.GitBinary = gitpath |
| 164 | 164 |
|
| 165 |
- config.AllowPush = os.Getenv("ALLOW_GIT_PUSH") != "no"
|
|
| 166 |
- config.AllowHooks = os.Getenv("ALLOW_GIT_HOOKS") != "no"
|
|
| 167 |
- config.AllowLazyCreate = os.Getenv("ALLOW_LAZY_CREATE") != "no"
|
|
| 165 |
+ config.AllowPush = os.Getenv("ALLOW_GIT_PUSH") != "false"
|
|
| 166 |
+ config.AllowHooks = os.Getenv("ALLOW_GIT_HOOKS") != "false"
|
|
| 167 |
+ config.AllowLazyCreate = os.Getenv("ALLOW_LAZY_CREATE") != "false"
|
|
| 168 | 168 |
|
| 169 | 169 |
if hookpath := os.Getenv("HOOK_PATH"); len(hookpath) != 0 {
|
| 170 | 170 |
path, err := filepath.Abs(hookpath) |
| ... | ... |
@@ -177,7 +200,7 @@ func NewEnviromentConfig() (*Config, error) {
|
| 177 | 177 |
config.HookDirectory = path |
| 178 | 178 |
} |
| 179 | 179 |
|
| 180 |
- allowAnonymousGet := os.Getenv("ALLOW_ANON_GIT_PULL") == "yes"
|
|
| 180 |
+ allowAnonymousGet := os.Getenv("ALLOW_ANON_GIT_PULL") == "true"
|
|
| 181 | 181 |
serverAuth := os.Getenv("REQUIRE_SERVER_AUTH")
|
| 182 | 182 |
gitAuth := os.Getenv("REQUIRE_GIT_AUTH")
|
| 183 | 183 |
if len(serverAuth) > 0 && len(gitAuth) > 0 {
|
| ... | ... |
@@ -206,8 +229,9 @@ func NewEnviromentConfig() (*Config, error) {
|
| 206 | 206 |
} |
| 207 | 207 |
|
| 208 | 208 |
config.AuthMessage = fmt.Sprintf("Authenticating against %s allow-push=%t anon-pull=%t", cfg.Host, config.AllowPush, allowAnonymousGet)
|
| 209 |
- config.AuthenticatorFn = auth.Authenticator(func(info auth.AuthInfo) (bool, error) {
|
|
| 209 |
+ authHandlerFn := auth.Authenticator(func(info auth.AuthInfo) (bool, error) {
|
|
| 210 | 210 |
if !info.Push && allowAnonymousGet {
|
| 211 |
+ glog.V(5).Infof("Allowing pull because anonymous get is enabled")
|
|
| 211 | 212 |
return true, nil |
| 212 | 213 |
} |
| 213 | 214 |
req := &authapi.LocalSubjectAccessReview{
|
| ... | ... |
@@ -223,6 +247,7 @@ func NewEnviromentConfig() (*Config, error) {
|
| 223 | 223 |
} |
| 224 | 224 |
req.Action.Verb = "create" |
| 225 | 225 |
} |
| 226 |
+ glog.V(5).Infof("Checking for %s permission on pods", req.Action.Verb)
|
|
| 226 | 227 |
res, err := osc.ImpersonateLocalSubjectAccessReviews(namespace, info.Password).Create(req) |
| 227 | 228 |
if err != nil {
|
| 228 | 229 |
if se, ok := err.(*errors.StatusError); ok {
|
| ... | ... |
@@ -230,9 +255,13 @@ func NewEnviromentConfig() (*Config, error) {
|
| 230 | 230 |
} |
| 231 | 231 |
return false, err |
| 232 | 232 |
} |
| 233 |
- //log.Printf("debug: server response allowed=%t message=%s", res.Allowed, res.Reason)
|
|
| 233 |
+ glog.V(5).Infof("server response allowed=%t message=%s", res.Allowed, res.Reason)
|
|
| 234 | 234 |
return res.Allowed, nil |
| 235 | 235 |
}) |
| 236 |
+ if allowAnonymousGet {
|
|
| 237 |
+ authHandlerFn = anonymousHandler(authHandlerFn) |
|
| 238 |
+ } |
|
| 239 |
+ config.AuthenticatorFn = authHandlerFn |
|
| 236 | 240 |
} |
| 237 | 241 |
|
| 238 | 242 |
if len(gitAuth) > 0 {
|
| ... | ... |
@@ -245,13 +274,16 @@ func NewEnviromentConfig() (*Config, error) {
|
| 245 | 245 |
config.AuthenticatorFn = auth.Authenticator(func(info auth.AuthInfo) (bool, error) {
|
| 246 | 246 |
if info.Push {
|
| 247 | 247 |
if !config.AllowPush {
|
| 248 |
+ glog.V(5).Infof("Denying push request because it is disabled in config.")
|
|
| 248 | 249 |
return false, nil |
| 249 | 250 |
} |
| 250 | 251 |
if allowAnonymousGet {
|
| 252 |
+ glog.V(5).Infof("Allowing pull because anonymous get is enabled")
|
|
| 251 | 253 |
return true, nil |
| 252 | 254 |
} |
| 253 | 255 |
} |
| 254 | 256 |
if info.Username != username || info.Password != password {
|
| 257 |
+ glog.V(5).Infof("Username or password doesn't match")
|
|
| 255 | 258 |
return false, nil |
| 256 | 259 |
} |
| 257 | 260 |
return true, nil |
| ... | ... |
@@ -262,7 +294,7 @@ func NewEnviromentConfig() (*Config, error) {
|
| 262 | 262 |
config.Listen = value |
| 263 | 263 |
} |
| 264 | 264 |
|
| 265 |
- config.CleanBeforeClone = os.Getenv("GIT_FORCE_CLEAN") == "yes"
|
|
| 265 |
+ config.CleanBeforeClone = os.Getenv("GIT_FORCE_CLEAN") == "true"
|
|
| 266 | 266 |
|
| 267 | 267 |
clones := make(map[string]Clone) |
| 268 | 268 |
for _, env := range os.Environ() {
|
| ... | ... |
@@ -324,6 +356,8 @@ func NewEnviromentConfig() (*Config, error) {
|
| 324 | 324 |
return nil, fmt.Errorf("%s name %q is reserved (%v)", key, name, reservedNames)
|
| 325 | 325 |
} |
| 326 | 326 |
|
| 327 |
+ glog.V(5).Infof("Adding initial clone to repo at %s", url.String())
|
|
| 328 |
+ |
|
| 327 | 329 |
clones[name] = Clone{
|
| 328 | 330 |
URL: *url, |
| 329 | 331 |
} |
| ... | ... |
@@ -333,6 +367,21 @@ func NewEnviromentConfig() (*Config, error) {
|
| 333 | 333 |
return config, nil |
| 334 | 334 |
} |
| 335 | 335 |
|
| 336 |
+func anonymousHandler(f func(http.Handler) http.Handler) func(http.Handler) http.Handler {
|
|
| 337 |
+ return func(h http.Handler) http.Handler {
|
|
| 338 |
+ authHandler := f(h) |
|
| 339 |
+ anonymousHandler := func(w http.ResponseWriter, req *http.Request) {
|
|
| 340 |
+ // If anonymous read request, simply serve content |
|
| 341 |
+ if req.FormValue("service") != "git-receive-pack" && len(req.Header.Get("Authorization")) == 0 {
|
|
| 342 |
+ h.ServeHTTP(w, req) |
|
| 343 |
+ return |
|
| 344 |
+ } |
|
| 345 |
+ authHandler.ServeHTTP(w, req) |
|
| 346 |
+ } |
|
| 347 |
+ return http.HandlerFunc(anonymousHandler) |
|
| 348 |
+ } |
|
| 349 |
+} |
|
| 350 |
+ |
|
| 336 | 351 |
func handler(config *Config) http.Handler {
|
| 337 | 352 |
git := githttp.New(config.Home) |
| 338 | 353 |
git.GitBinPath = config.GitBinary |
| ... | ... |
@@ -365,6 +414,7 @@ func Start(config *Config) error {
|
| 365 | 365 |
|
| 366 | 366 |
ops := http.NewServeMux() |
| 367 | 367 |
if config.AllowHooks {
|
| 368 |
+ glog.V(5).Infof("Installing handler for the /_/hooks endpoint")
|
|
| 368 | 369 |
ops.Handle("/hooks/", prometheus.InstrumentHandler("hooks", http.StripPrefix("/hooks", hooksHandler(config))))
|
| 369 | 370 |
} |
| 370 | 371 |
/*ops.Handle("/reflect/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
| ... | ... |
@@ -372,6 +422,7 @@ func Start(config *Config) error {
|
| 372 | 372 |
fmt.Fprintf(os.Stdout, "%s %s\n", r.Method, r.URL) |
| 373 | 373 |
io.Copy(os.Stdout, r.Body) |
| 374 | 374 |
}))*/ |
| 375 |
+ glog.V(5).Infof("Installing handler for the /_/metrics endpoint")
|
|
| 375 | 376 |
ops.Handle("/metrics", prometheus.UninstrumentedHandler())
|
| 376 | 377 |
healthz.InstallHandler(ops) |
| 377 | 378 |
|
| ... | ... |
@@ -380,8 +431,8 @@ func Start(config *Config) error {
|
| 380 | 380 |
mux.Handle("/_/", http.StripPrefix("/_", ops))
|
| 381 | 381 |
|
| 382 | 382 |
if len(config.AuthMessage) > 0 {
|
| 383 |
- log.Printf("%s", config.AuthMessage)
|
|
| 383 |
+ glog.Infof("%s", config.AuthMessage)
|
|
| 384 | 384 |
} |
| 385 |
- log.Printf("Serving %s on %s", config.Home, config.Listen)
|
|
| 385 |
+ glog.Infof("Serving %s on %s", config.Home, config.Listen)
|
|
| 386 | 386 |
return http.ListenAndServe(config.Listen, mux) |
| 387 | 387 |
} |
| ... | ... |
@@ -12,6 +12,8 @@ import ( |
| 12 | 12 |
"regexp" |
| 13 | 13 |
"strings" |
| 14 | 14 |
|
| 15 |
+ "github.com/golang/glog" |
|
| 16 |
+ |
|
| 15 | 17 |
"github.com/openshift/origin/pkg/generate/git" |
| 16 | 18 |
) |
| 17 | 19 |
|
| ... | ... |
@@ -35,6 +37,9 @@ func lazyInitRepositoryHandler(config *Config, handler http.Handler) http.Handle |
| 35 | 35 |
handler.ServeHTTP(w, r) |
| 36 | 36 |
return |
| 37 | 37 |
} |
| 38 |
+ if !strings.HasSuffix(name, ".git") {
|
|
| 39 |
+ name += ".git" |
|
| 40 |
+ } |
|
| 38 | 41 |
path := filepath.Join(config.Home, name) |
| 39 | 42 |
_, err := os.Stat(path) |
| 40 | 43 |
if !os.IsNotExist(err) {
|
| ... | ... |
@@ -70,6 +75,8 @@ func lazyInitRepositoryHandler(config *Config, handler http.Handler) http.Handle |
| 70 | 70 |
func RepositoryURL(config *Config, name string, r *http.Request) *url.URL {
|
| 71 | 71 |
var url url.URL |
| 72 | 72 |
switch {
|
| 73 |
+ case config.InternalURL != nil: |
|
| 74 |
+ url = *config.InternalURL |
|
| 73 | 75 |
case config.URL != nil: |
| 74 | 76 |
url = *config.URL |
| 75 | 77 |
case r != nil: |
| ... | ... |
@@ -89,49 +96,62 @@ func newRepository(config *Config, path string, hooks map[string]string, self *u |
| 89 | 89 |
var out []byte |
| 90 | 90 |
repo := git.NewRepositoryForBinary(config.GitBinary) |
| 91 | 91 |
|
| 92 |
+ barePath := path |
|
| 93 |
+ if !strings.HasSuffix(barePath, ".git") {
|
|
| 94 |
+ barePath += ".git" |
|
| 95 |
+ } |
|
| 96 |
+ aliasPath := strings.TrimSuffix(barePath, ".git") |
|
| 97 |
+ |
|
| 92 | 98 |
if origin != nil {
|
| 93 |
- if err := repo.CloneMirror(path, origin.String()); err != nil {
|
|
| 99 |
+ if err := repo.CloneMirror(barePath, origin.String()); err != nil {
|
|
| 94 | 100 |
return out, err |
| 95 | 101 |
} |
| 96 | 102 |
} else {
|
| 97 |
- if err := repo.Init(path, true); err != nil {
|
|
| 103 |
+ if err := repo.Init(barePath, true); err != nil {
|
|
| 98 | 104 |
return out, err |
| 99 | 105 |
} |
| 100 | 106 |
} |
| 101 | 107 |
|
| 102 | 108 |
if self != nil {
|
| 103 |
- if err := repo.AddLocalConfig(path, "gitserver.self.url", self.String()); err != nil {
|
|
| 109 |
+ if err := repo.AddLocalConfig(barePath, "gitserver.self.url", self.String()); err != nil {
|
|
| 104 | 110 |
return out, err |
| 105 | 111 |
} |
| 106 | 112 |
} |
| 107 | 113 |
|
| 108 | 114 |
// remove all sample hooks, ignore errors here |
| 109 |
- if files, err := ioutil.ReadDir(filepath.Join(path, "hooks")); err == nil {
|
|
| 115 |
+ if files, err := ioutil.ReadDir(filepath.Join(barePath, "hooks")); err == nil {
|
|
| 110 | 116 |
for _, file := range files {
|
| 111 |
- os.Remove(filepath.Join(path, "hooks", file.Name())) |
|
| 117 |
+ os.Remove(filepath.Join(barePath, "hooks", file.Name())) |
|
| 112 | 118 |
} |
| 113 | 119 |
} |
| 114 | 120 |
|
| 115 | 121 |
for name, hook := range hooks {
|
| 116 |
- dest := filepath.Join(path, "hooks", name) |
|
| 122 |
+ dest := filepath.Join(barePath, "hooks", name) |
|
| 117 | 123 |
if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
|
| 118 | 124 |
return out, err |
| 119 | 125 |
} |
| 126 |
+ glog.V(5).Infof("Creating hook symlink %s -> %s", dest, hook)
|
|
| 120 | 127 |
if err := os.Symlink(hook, dest); err != nil {
|
| 121 | 128 |
return out, err |
| 122 | 129 |
} |
| 123 | 130 |
} |
| 124 | 131 |
|
| 125 | 132 |
if initHook, ok := hooks["init"]; ok {
|
| 133 |
+ glog.V(5).Infof("Init hook exists, invoking it")
|
|
| 126 | 134 |
cmd := exec.Command(initHook) |
| 127 |
- cmd.Dir = path |
|
| 135 |
+ cmd.Dir = barePath |
|
| 128 | 136 |
result, err := cmd.CombinedOutput() |
| 137 |
+ glog.V(5).Infof("Init output:\n%s", result)
|
|
| 129 | 138 |
if err != nil {
|
| 130 | 139 |
return out, fmt.Errorf("init hook failed: %v\n%s", err, string(result))
|
| 131 | 140 |
} |
| 132 | 141 |
out = result |
| 133 | 142 |
} |
| 134 | 143 |
|
| 144 |
+ if err := os.Symlink(barePath, aliasPath); err != nil {
|
|
| 145 |
+ return out, fmt.Errorf("cannot create alias path %s: %v", aliasPath, err)
|
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 135 | 148 |
return out, nil |
| 136 | 149 |
} |
| 137 | 150 |
|
| ... | ... |
@@ -183,6 +203,7 @@ func clone(config *Config) error {
|
| 183 | 183 |
} |
| 184 | 184 |
|
| 185 | 185 |
func loadHooks(path string) (map[string]string, error) {
|
| 186 |
+ glog.V(5).Infof("Loading hooks from directory %s", path)
|
|
| 186 | 187 |
hooks := make(map[string]string) |
| 187 | 188 |
if len(path) == 0 {
|
| 188 | 189 |
return hooks, nil |
| ... | ... |
@@ -197,6 +218,7 @@ func loadHooks(path string) (map[string]string, error) {
|
| 197 | 197 |
} |
| 198 | 198 |
hook := filepath.Join(path, file.Name()) |
| 199 | 199 |
name := filepath.Base(hook) |
| 200 |
+ glog.V(5).Infof("Adding hook %s at %s", name, hook)
|
|
| 200 | 201 |
hooks[name] = hook |
| 201 | 202 |
} |
| 202 | 203 |
return hooks, nil |