Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Add install script for those not using devcontainer (#322)
Browse files Browse the repository at this point in the history
This installs the tools to `$clone/hack/tools` instead. There is a `dev.sh` script to run to get into a shell with a `PATH` pointing to the right place.
  • Loading branch information
Porges authored Nov 12, 2020
1 parent 666b722 commit e2be304
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 37 deletions.
41 changes: 9 additions & 32 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,21 @@ RUN apt-get update \
# RUN curl -fsSL https://get.docker.com | sh -
# RUN usermod -aG docker vscode

# Go dependencies
ENV GO111MODULE=on
RUN mkdir -p /tmp/gotools \
&& export GOPATH=/tmp/gotools \
&& export GOCACHE=/tmp/gotools/cache \
&& go get \
# go tools for vscode are preinstalled by base image (see first comment in Dockefile)
# golangci-lint is provided by base image
github.com/jandelgado/[email protected] \
github.com/mitchellh/[email protected] \
k8s.io/code-generator/cmd/[email protected] \
sigs.k8s.io/controller-tools/cmd/[email protected] \
sigs.k8s.io/[email protected] \
sigs.k8s.io/kustomize/kustomize/[email protected] \
&& mv /tmp/gotools/bin/* /usr/local/bin/ \
&& rm -rf /tmp/gotools

# install kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.19.0/bin/linux/amd64/kubectl \
&& chmod +x ./kubectl \
&& mv ./kubectl /usr/local/bin/kubectl

# install go-task (as task runner)
RUN curl -sL "https://github.com/go-task/task/releases/download/v3.0.0/task_linux_amd64.tar.gz" | tar xz -C /usr/local/bin task
RUN curl -sL "https://raw.githubusercontent.com/go-task/task/v3.0.0/completion/bash/task.bash" > "/home/vscode/.oh-my-bash/completions/task.completion.sh"
COPY install-dependencies.sh .
RUN ./install-dependencies.sh devcontainer && rm install-dependencies.sh

# install kubebuilder
RUN os=$(go env GOOS) \
&& arch=$(go env GOARCH) \
&& curl -L https://go.kubebuilder.io/dl/2.3.1/${os}/${arch} | tar -xz -C /tmp/ \
&& mv /tmp/kubebuilder_2.3.1_${os}_${arch} /usr/local/kubebuilder
# Add kubebuilder to PATH
ENV PATH=$PATH:/usr/local/kubebuilder/bin

# add bash customizations
# Add further bash customizations
# note that the base image includes oh-my-bash, we are enabling plugins here
RUN sed -i '/^plugins=/a kubectl\ngolang' "/home/vscode/.bashrc"
RUN sed -i '/^completions=/a kubectl\ngo\ntask' "/home/vscode/.bashrc"
# make kubectl completions work with 'k' alias

# Make kubectl completions work with 'k' alias
RUN echo 'complete -F __start_kubectl k' >> "/home/vscode/.bashrc"

# Setup go-task completions
RUN curl -sL "https://raw.githubusercontent.com/go-task/task/v3.0.0/completion/bash/task.bash" > "/home/vscode/.oh-my-bash/completions/task.completion.sh"

ENV KIND_CLUSTER_NAME=k8sinfra
85 changes: 85 additions & 0 deletions .devcontainer/install-dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/sh

set -eu

# This script must run in two modes:
#
# - When being used to set up a devcontainer.
# In this mode the code is not checked out yet,
# and we can install the tools globally.
#
# - When being used to install tools locally.
# In this mode the code is already checked out,
# and we do not want to pollute the user’s system.
#
# To distinguish between these modes we will
# have the devcontainer script pass an argument:

if [ "$1" = "devcontainer" ]; then
TOOL_DEST=/usr/local/bin
KUBEBUILDER_DEST=/usr/local/kubebuilder
else
TOOL_DEST=$(git rev-parse --show-toplevel)/hack/tools
mkdir -p "$TOOL_DEST"
KUBEBUILDER_DEST="$TOOL_DEST/kubebuilder"
fi

if ! command -v go > /dev/null 2>&1; then
echo "Go must be installed manually: https://golang.org/doc/install"
exit 1
fi

if ! command -v az > /dev/null 2>&1; then
echo "Azure CLI must be installed manually: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"
exit 1
fi

echo "Installing tools to $TOOL_DEST"

# Install Go tools
TMPDIR=$(mktemp -d)
clean() {
rm -rf "$TMPDIR"
}
trap clean EXIT

export GOBIN=$TOOL_DEST
export GOPATH=$TMPDIR
export GOCACHE=$TMPDIR/cache
export GO111MODULE=on

echo "Installing Go tools…"

# go tools for vscode are preinstalled by base image (see first comment in Dockerfile)
go get \
github.com/jandelgado/[email protected] \
github.com/mitchellh/[email protected] \
k8s.io/code-generator/cmd/[email protected] \
sigs.k8s.io/controller-tools/cmd/[email protected] \
sigs.k8s.io/[email protected] \
sigs.k8s.io/kustomize/kustomize/[email protected]

if [ "$1" != "devcontainer" ]; then
echo "Installing golangci-lint…"
# golangci-lint is provided by base image if in devcontainer
# this command copied from there
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$TOOL_DEST" 2>&1
fi

echo "Installing kubectl…"
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.19.0/bin/linux/amd64/kubectl \
&& chmod +x ./kubectl \
&& mv ./kubectl "$TOOL_DEST/kubectl"

# Install go-task (task runner)
echo "Installing go-task…"
curl -sL "https://github.com/go-task/task/releases/download/v3.0.0/task_linux_amd64.tar.gz" | tar xz -C "$TOOL_DEST" task

# Install kubebuilder
echo "Installing kubebuilder…"
os=$(go env GOOS)
arch=$(go env GOARCH)
curl -L "https://go.kubebuilder.io/dl/2.3.1/${os}/${arch}" | tar -xz -C /tmp/
mv "/tmp/kubebuilder_2.3.1_${os}_${arch}" "$KUBEBUILDER_DEST"

echo "Installed tools: $(ls "$TOOL_DEST")"
18 changes: 18 additions & 0 deletions dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh

set -eu

GIT_ROOT=$(git rev-parse --show-toplevel)
TOOL_DEST=$GIT_ROOT/hack/tools

if [ ! -f "$TOOL_DEST/task" ]; then # check for local installation
if [ ! -f "/usr/local/bin/task" ]; then # or devcontainer installation
$GIT_ROOT/.devcontainer/install-dependencies.sh local # otherwise, install the tools
fi
fi

export PATH="$PATH:$TOOL_DEST:$TOOL_DEST/kubebuilder/bin"

echo "Entering $SHELL with expanded PATH (use 'exit' to quit):"
echo "Try running 'task -l' to see possible commands."
$SHELL
57 changes: 52 additions & 5 deletions hack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
## Developer setup (with VS Code)
This repository contains a [devcontainer](https://code.visualstudio.com/docs/remote/containers) configuration that can be used in conjunction with VS Code to set up an environment with all the required tools preinstalled.

This is the recommended setup, especially if you are using Windows as your development platform.

If you want to use this:

0. Make sure you have installed [the prerequisites to use Docker](https://code.visualstudio.com/docs/remote/containers#_system-requirements), including WSL if on Windows.
1. Install VS Code and the [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension (check installation instructions there).
2. Run the VS Code command (with `Ctrl-Shift-P`): `Remote Containers: Clone Repository in Container Volume...`

**Note**: in Windows, it is important to clone directly into a container instead of cloning first and then loading that with the `Remote Containers` extension, as the tooling performs a lot of file I/O and if this is performed against a volume mounted in WSL, then it is unusably slow.
**Note**: in Windows, it is important to clone directly into a container instead of cloning first and then loading that with the `Remote Containers` extension, as the tooling performs a lot of file I/O, and if this is performed against a volume mounted in WSL then it is unusably slow.

To complete the clone:
1. Select "`GitHub`".
Expand All @@ -19,12 +21,57 @@ If you want to use this:

3. To validate everything is working correctly, you can open a terminal in VS Code and run `task -l`. This will show a list of all `task` commands. Running `task` by itself (or `task default`) will run quick local pre-checkin tests and validation.

### Without VS Code
## Without VS Code

### Dockerfile

The same `Dockerfile` that the VS Code `devcontainer` extension uses can also be used outside of VS Code; it is stored in the root `.devcontainer` directory and can be used to create a development container with all the tooling preinstalled:

```console
$ docker build $(git rev-parse --show-toplevel)/.devcontainer -t k8sinfradev:latest
… image will be created …

$ # After that you can start a terminal in the development container with:
$ docker run -v $(git rev-parse --show-toplevel):/go/src -w /go/src -u $(id -u ${USER}):$(id -g ${USER}) -it k8sinfradev:latest
```

It is not recommended to mount the source like this on Windows (WSL2) as the cross-VM file operations are very slow.

### ./dev.sh

The same `Dockerfile` can also be used if you are not using VS Code; it is stored in the root `.devcontainer` directory and can be used to create a development container with all the tooling preinstalled.
If you are using Linux, instead of using VS Code you can run the `dev.sh` script in the root of the repository. This will install all required tooling into the `hack/tools` directory and then start a new shell with the `PATH` updated to use it.

## Running integration tests

Run `task generated:test-integration-envtest`.
Basic use: run `task controller:test-integration-envtest`.

### Record/replay

The task `controller:test-integration-envtest` runs the tests in a record/replay mode by default, so that it does not touch any live Azure resources. (This uses the [go-vcr](https://github.com/dnaeon/go-vcr) library.) If you change the controller or other code in such a way that the required requests/responses from ARM change, you will need to update the recordings.

To do this, delete the recordings for the failing tests (under `{test-dir}/recordings/{test-name}.yml`), and re-run `controller:test-integration-envtest`. If the test passes, a new recording will be saved, which you can commit to include with your change. All authentication and subscription information is removed from the recording.

To run the test and produce a new recording you will also need to have set the required authentication environment variables for an Azure Service Principal: `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET`. This Service Principal will need access to the subscription to create and delete resources.

If you need to create a new Azure Service Principal, run the following commands:

```console
$ az login
… follow the instructions …
$ az account set --subscription {the subscription ID you would like to use}
Creating a role assignment under the scope of "/subscriptions/{subscription ID you chose}"
$ az ad sp create-for-rbac --role contributor --name {the name you would like to use}
{
"appId": "…",
"displayName": "{name you chose}",
"name": "{name you chose}",
"password": "…",
"tenant": "…"
}
```
The output contains `appId` (`AZURE_CLIENT_ID`), `password` (`AZURE_CLIENT_SECRET`), and `tenant` (`AZURE_TENANT_ID`). Store these somewhere safe as the password cannot be viewed again, only reset. The Service Principal will be created as a “contributor” to your subscription which means it can create and delete resources, so **ensure you keep the secrets secure**.

### Running live tests

TODO: instructions on record/replay usage, etc.
If you want to skip all recordings and run all tests directly against live Azure resources, you can use the `controller:test-integration-envtest-live` task. This will also require you to set the authentication environment variables, as detailed above.
3 changes: 3 additions & 0 deletions workspace.code-workspace
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"folders": [
{
"path": "."
},
{
"path": "hack/generated"
},
Expand Down

0 comments on commit e2be304

Please sign in to comment.