Skip to content

Commit e35b3e3

Browse files
committed
squash all commits
0 parents  commit e35b3e3

18 files changed

+2085
-0
lines changed

.buildkite/hooks/pre-command

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu
4+
pushd "$(dirname "${BASH_SOURCE[0]}")"/../..
5+
6+
TOOL_VERSION_FILES=()
7+
mapfile -d $'\0' TOOL_VERSION_FILES < <(fd .tool-versions --hidden --absolute-path --print0)
8+
9+
for file in "${TOOL_VERSION_FILES[@]}"; do
10+
echo "Installing asdf dependencies as defined in ${file}:"
11+
parent=$(dirname "${file}")
12+
pushd "${parent}"
13+
14+
asdf install
15+
16+
popd
17+
done
18+
19+
popd

.buildkite/pipeline.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
steps:
2+
- label: ':lipstick:'
3+
command: .buildkite/prettier-check.sh

.buildkite/prettier-check.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
cd "$(dirname "${BASH_SOURCE[0]}")"/..
4+
set -euxo pipefail
5+
6+
yarn
7+
8+
yarn run prettier-check

.gitignore

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/bin/
2+
/node_modules/
3+
yarn-error.log
4+
5+
.vscode/*
6+
!.vscode/settings.json
7+
!.vscode/tasks.json
8+
!.vscode/launch.json
9+
!.vscode/extensions.json
10+
11+
.history
12+
13+
.envrc
14+
15+
Pulumi.dev.yaml

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
12.16.1

.tool-versions

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
yarn 1.22.4
2+
kubectl 1.17.3
3+
fd 7.4.0
4+
pulumi 1.14.0

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"editor.formatOnSave": true
3+
}

Pulumi.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name: sourcegraph-deploy-kubernetes-helper
2+
runtime: nodejs
3+
description: A small helper program to aid in creating a test cluster for https://github.com/sourcegraph/deploy-sourcegraph.

README.md

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# deploy-k8s-helper
2+
3+
A small helper program to aid in creating a test cluster for https://github.com/sourcegraph/deploy-sourcegraph.
4+
5+
## Prerequisites
6+
7+
- [Pulumi](https://pulumi.io/quickstart/install.html)
8+
- Run `pulumi login` after installation
9+
- [Yarn](https://yarnpkg.com/en/)
10+
- GCP access to the ["Sourcegraph Auxiliary" (sourcegraph-server) GCP project](https://console.cloud.google.com/kubernetes/list?project=sourcegraph-server)
11+
- Run `gcloud auth application-default login` to fetch the necessary credentials for Pulumi to use
12+
- https://github.com/sourcegraph/deploy-sourcegraph checked out on your local machine
13+
- deploy-k8s-helper reads the contents of that directory. Make sure your that your checkout is up-to-date!
14+
15+
### Configuration
16+
17+
See [config.ts](config.ts) for more information, but you **must** set the following configuration values via `pulumi config set <NAME> <VALUE>`
18+
19+
- `gcloudEmail` - The email that you use to sign in to our GCP project.
20+
- example: [email protected]
21+
- `deploySourcegraphRoot` - The path to the root of your https://github.com/sourcegraph/deploy-sourcegraph checkout.
22+
- example: /Users/ggilmore/dev/go/src/github.com/sourcegraph/deploy-sourcegraph
23+
24+
## Usage
25+
26+
Run `yarn` so that you install all the necessary dependencies.
27+
28+
- `yarn up`: creates a new GKE cluster and fetches the necessary credentials
29+
- `yarn destroy`: deletes a GKE cluster that was previously created with `yarn up`
30+
- `yarn auth`: fetch the credentials so that kubectl can speak to the cluster
31+
- `yarn deauth`: remove the cluster's kubectl credentials
32+
- `yarn web`: opens the GCP page for your cluster in your webrowser
33+
34+
## Troubleshooting
35+
36+
### The zone '...' doesn't have enough resources to fulfill the request
37+
38+
Example:
39+
40+
```
41+
Do you want to perform this update? yes
42+
Updating (dev):
43+
44+
Type Name Status Info
45+
+ pulumi:pulumi:Stack sg-deploy-k8s-helper-dev **creating failed** 1 error
46+
+ └─ gcp:container:Cluster geoffrey-sourcegraph-test **creating failed** 1 error
47+
48+
Diagnostics:
49+
pulumi:pulumi:Stack (sg-deploy-k8s-helper-dev):
50+
error: update failed
51+
52+
gcp:container:Cluster (geoffrey-sourcegraph-test):
53+
error: Plan apply failed: Error waiting for creating GKE cluster: Deploy error: Not all instances running in IGM after 46.650887217s. Expect 4. Current errors: [ZONE_RESOURCE_POOL_EXHAUSTED_WITH_DETAILS]: Instance 'gke-geoffrey-sourcegraph-default-pool-7f493867-0bmt' creation failed: The zone 'projects/sourcegraph-server/zones/us-central1-a' does not have enough resources available to fulfill the request. '(resource type:compute)'. - ; .
54+
```
55+
56+
Solution: Pick another zone to use from https://cloud.google.com/compute/docs/regions-zones/#available. Set it in your stack configuration by running `pulumi config set gcp:zone [NEW_ZONE]`
57+
58+
### (ingress-nginx) Cannot read property 'status' of undefined
59+
60+
This happens if you're trying to deploy a pre-`3.x` release of https://github.com/sourcegraph/deploy-sourcegraph/ (which didn't have `nginx-ingress`).
61+
62+
Example:
63+
64+
```
65+
Diagnostics:
66+
pulumi:pulumi:Stack (sg-deploy-k8s-helper-dev):
67+
error: Running program '/Users/ggilmore/dev/go/src/github.com/sourcegraph/ds-k8s-helper' failed with an unhandled exception:
68+
TypeError: Cannot read property 'status' of undefined
69+
at exports.ingressIPs.ingressNginx.getResource.apply.svc (/Users/ggilmore/dev/go/src/github.com/sourcegraph/ds-k8s-helper/index.ts:49:23)
70+
at OutputImpl.<anonymous> (/Users/ggilmore/dev/go/src/github.com/sourcegraph/ds-k8s-helper/node_modules/@pulumi/kubernetes/node_modules/@pulumi/pulumi/output.js:102:47)
71+
at Generator.next (<anonymous>)
72+
at fulfilled (/Users/ggilmore/dev/go/src/github.com/sourcegraph/ds-k8s-helper/node_modules/@pulumi/kubernetes/node_modules/@pulumi/pulumi/output.js:17:58)
73+
```
74+
75+
Solution: Comment out the `const ingressNginx` and `export const ingressIPs` variables in https://github.com/sourcegraph/deploy-k8s-helper/blob/master/index.ts : https://github.com/sourcegraph/deploy-k8s-helper/blob/87bce4bb4f4448336a5b7feabca23bf1747b9fda/index.ts#L61-L72

cluster.ts

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as gcp from '@pulumi/gcp'
2+
import * as k8s from '@pulumi/kubernetes'
3+
import * as pulumi from '@pulumi/pulumi'
4+
5+
import * as os from 'os'
6+
import { URL } from 'url'
7+
8+
import { clusterConfig, gcloudConfig } from './config'
9+
10+
const name = clusterConfig.name || `${os.userInfo().username}-sourcegraph-test`
11+
12+
const cluster = new gcp.container.Cluster(name, {
13+
// Don't auto-generate a name iff the user explicitly defined one.
14+
name: clusterConfig.name,
15+
16+
description: 'Scratch cluster used for testing sourcegraph/deploy-sourcegraph',
17+
18+
location: gcloudConfig.location,
19+
project: gcloudConfig.project,
20+
21+
initialNodeCount: clusterConfig.nodeCount,
22+
removeDefaultNodePool: true,
23+
24+
nodeConfig: {
25+
diskType: 'pd-ssd',
26+
localSsdCount: 1,
27+
machineType: clusterConfig.machineType,
28+
29+
oauthScopes: [
30+
'https://www.googleapis.com/auth/compute',
31+
'https://www.googleapis.com/auth/devstorage.read_only',
32+
'https://www.googleapis.com/auth/logging.write',
33+
'https://www.googleapis.com/auth/monitoring',
34+
],
35+
},
36+
})
37+
38+
export const clusterContext = pulumi
39+
.all([cluster.name, cluster.location, cluster.project])
40+
.apply(([name, location, project]) => `gke_${project}_${location}_${name}`)
41+
42+
export const kubeconfig = pulumi
43+
.all([clusterContext, cluster.endpoint, cluster.masterAuth])
44+
.apply(([context, endpoint, masterAuth]) => {
45+
return `apiVersion: v1
46+
clusters:
47+
- cluster:
48+
certificate-authority-data: ${masterAuth.clusterCaCertificate}
49+
server: https://${endpoint}
50+
name: ${context}
51+
contexts:
52+
- context:
53+
cluster: ${context}
54+
user: ${context}
55+
name: ${context}
56+
current-context: ${context}
57+
kind: Config
58+
preferences: {}
59+
users:
60+
- name: ${context}
61+
user:
62+
auth-provider:
63+
config:
64+
cmd-args: config config-helper --format=json
65+
cmd-path: gcloud
66+
expiry-key: '{.credential.token_expiry}'
67+
token-key: '{.credential.access_token}'
68+
name: gcp
69+
`
70+
})
71+
72+
export const gcloudAuthCommand = pulumi
73+
.all([cluster.name, cluster.location, cluster.project])
74+
.apply(
75+
([name, location, project]) =>
76+
`gcloud container clusters get-credentials ${name} --location ${location} --project ${project}`
77+
)
78+
79+
export const gcpURL = pulumi
80+
.all([cluster.name, cluster.location, cluster.project])
81+
.apply(([name, location, project]) => {
82+
const url = new URL(`${location}/${name}`, 'https://console.cloud.google.com/kubernetes/clusters/details/')
83+
url.searchParams.set('project', project)
84+
return url.toString()
85+
})
86+
87+
export const k8sProvider = new k8s.Provider(name, {
88+
kubeconfig,
89+
})

config.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as gcp from '@pulumi/gcp'
2+
import * as pulumi from '@pulumi/pulumi'
3+
4+
const config = new pulumi.Config()
5+
6+
export const clusterConfig = {
7+
/**
8+
* The name for the GKE cluster. A name will be auto-generated
9+
* for the cluster if the configuation value is undefefined.
10+
*/
11+
name: config.get('clusterName'),
12+
13+
/**
14+
* The number of nodes to create in this cluster.
15+
* Defaults to 4.
16+
*/
17+
nodeCount: config.getNumber('nodeCount') || 4,
18+
19+
/**
20+
* The name of a Google Compute Engine machine type.
21+
* Defaults to n1-standard-8.
22+
*/
23+
machineType: config.get('machineType') || 'n1-standard-8',
24+
}
25+
26+
export const gcloudConfig = {
27+
/**
28+
* The name of the GCP Project to create the cluster inside of.
29+
* Defaults to 'sourcegraph-server' (Sourcegraph Auxiliary).
30+
*/
31+
project: gcp.config.project || 'sourcegraph-server',
32+
33+
/**
34+
* The name of the GCP zone to create the cluster inside of.
35+
* Defaults to 'us-central1-a'.
36+
*/
37+
location: gcp.config.zone || 'us-central1-a',
38+
39+
/**
40+
* The email that you use to sign in to our GCP project.
41+
* Example: [email protected]
42+
*/
43+
username: config.require('gcloudEmail'),
44+
}
45+
46+
/**
47+
* The path to the root of your sourcegraph/deploy-sourcegraph checkout.
48+
* Example: /Users/ggilmore/dev/go/src/github.com/sourcegraph/deploy-sourcegraph
49+
*/
50+
export const deploySourcegraphRoot = config.require('deploySourcegraphRoot')

index.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as os from 'os'
2+
import * as path from 'path'
3+
4+
import * as k8s from '@pulumi/kubernetes'
5+
6+
import { k8sProvider } from './cluster'
7+
import { deploySourcegraphRoot, gcloudConfig } from './config'
8+
9+
const clusterAdmin = new k8s.rbac.v1.ClusterRoleBinding(
10+
'cluster-admin-role-binding',
11+
{
12+
metadata: { name: `${os.userInfo().username}-cluster-admin-role-binding` },
13+
14+
roleRef: {
15+
apiGroup: 'rbac.authorization.k8s.io',
16+
kind: 'ClusterRole',
17+
name: 'cluster-admin',
18+
},
19+
20+
subjects: [
21+
{
22+
apiGroup: 'rbac.authorization.k8s.io',
23+
kind: 'User',
24+
name: gcloudConfig.username,
25+
},
26+
],
27+
},
28+
{ provider: k8sProvider }
29+
)
30+
31+
const storageClass = new k8s.storage.v1.StorageClass(
32+
'sourcegraph-storage-class',
33+
{
34+
metadata: {
35+
name: 'sourcegraph',
36+
37+
labels: {
38+
deploy: 'sourcegraph',
39+
},
40+
},
41+
provisioner: 'kubernetes.io/gce-pd',
42+
43+
parameters: {
44+
type: 'pd-ssd',
45+
},
46+
},
47+
{ provider: k8sProvider }
48+
)
49+
50+
const baseDeployment = new k8s.yaml.ConfigGroup(
51+
'base',
52+
{
53+
files: `${path.posix.join(deploySourcegraphRoot, 'base')}/**/*.yaml`,
54+
},
55+
{
56+
providers: { kubernetes: k8sProvider },
57+
dependsOn: [clusterAdmin, storageClass],
58+
}
59+
)
60+
61+
const ingressNginx = new k8s.yaml.ConfigGroup(
62+
'ingress-nginx',
63+
{
64+
files: `${path.posix.join(deploySourcegraphRoot, 'configure', 'ingress-nginx')}/**/*.yaml`,
65+
},
66+
{ providers: { kubernetes: k8sProvider }, dependsOn: clusterAdmin }
67+
)
68+
69+
export const ingressIPs = ingressNginx
70+
.getResource('v1/Service', 'ingress-nginx', 'ingress-nginx')
71+
.apply(svc => svc.status.apply(status => status.loadBalancer.ingress.map(i => i.ip)))
72+
73+
export * from './cluster'

package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "sg-deploy-k8s-helper",
3+
"scripts": {
4+
"up": "pulumi up",
5+
"postup": "yarn auth",
6+
"destroy": "pulumi destroy",
7+
"predestroy": "yarn deauth",
8+
"auth": "$(pulumi stack output gcloudAuthCommand)",
9+
"deauth": "kubectl config delete-context $(pulumi stack output clusterContext)",
10+
"web": "opn $(pulumi stack output gcpURL)",
11+
"prettier": "prettier '**/{*.{js?(on),ts?(x),graphql,md,scss},.*.js?(on)}' --write --list-different --config prettier.config.js",
12+
"prettier-check": "yarn -s run prettier --write=false"
13+
},
14+
"devDependencies": {
15+
"@sourcegraph/prettierrc": "3.0.3",
16+
"@types/node": "latest",
17+
"opn-cli": "4.1.0",
18+
"prettier": "2.0.4",
19+
"tslint": "5.20.1",
20+
"tslint-config-prettier": "1.18.0"
21+
},
22+
"dependencies": {
23+
"@pulumi/gcp": "2.12.0",
24+
"@pulumi/kubernetes": "1.6.0",
25+
"@pulumi/pulumi": "1.14.0"
26+
}
27+
}

prettier.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require("@sourcegraph/prettierrc");

0 commit comments

Comments
 (0)