Skip to content

Commit

Permalink
Add a single source of CI and release configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
maxsokolovsky committed Dec 7, 2023
1 parent 72f5837 commit 0cf1275
Show file tree
Hide file tree
Showing 23 changed files with 441 additions and 21 deletions.
9 changes: 7 additions & 2 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,13 @@ RUN if [ "${ARCH}" == "amd64" ]; then \
curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/spectrometer/master/install.sh | sh; \
fi

# install controller-tools for crd generation
RUN go install sigs.k8s.io/controller-tools/cmd/[email protected]
# Tool for CRD generation.
ENV CONTROLLER_GEN_VERSION v0.12.0
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@${CONTROLLER_GEN_VERSION}

# YAML processor for release configuration.
ENV YQ_VERSION v4.40.2
RUN wget -q https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${ARCH}.tar.gz -O - | tar xz && mv yq_linux_${ARCH} /usr/bin/yq

ENV HELM_URL_V2_amd64=https://github.com/rancher/helm/releases/download/${CATTLE_HELM_VERSION}/rancher-helm \
HELM_URL_V2_arm64=https://github.com/rancher/helm/releases/download/${CATTLE_HELM_VERSION}/rancher-helm-arm64 \
Expand Down
4 changes: 4 additions & 0 deletions README-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ This repo is a meta-repo used for packaging and contains the majority of Rancher

Rancher also includes other open source libraries and projects, [see go.mod](https://github.com/rancher/rancher/blob/release/v2.8/go.mod) for the full list.

## Build configuration

Refer to the [build docs](docs/build.md) on how to customize the building and packaging of Rancher.

## Support, Discussion, and Community
If you need any help with Rancher, please join us at either our [Rancher forums](http://forums.rancher.com/) or [Slack](https://slack.rancher.io/) where most of our team hangs out at.

Expand Down
4 changes: 4 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
webhookVersion: 103.0.1+up0.4.2
cspAdapterMinVersion: 103.0.0+up3.0.0
defaultShellVersion: rancher/shell:v0.1.22
fleetVersion: 103.1.0+up0.9.0
8 changes: 7 additions & 1 deletion dev-scripts/build-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set -eo pipefail
set -x

SCRIPT_DIR="$(cd "$(dirname "$0")"; pwd)"
source "$SCRIPT_DIR/../scripts/export-config"

TARGET_OS="${TARGET_OS:-linux}"
GO_BINARY="${GO_BINARY:-$(which go)}"
Expand Down Expand Up @@ -56,4 +57,9 @@ cp "${K3S_AIRGAP_IMAGES_TARBALL}" "${PACKAGE_FOLDER}"

DOCKERFILE="${SCRIPT_DIR}/../package/Dockerfile"
# Always use buildx to make sure the image & the binary architectures match
docker buildx build -t "${TARGET_REPO}" -f "${DOCKERFILE}" "${PACKAGE_FOLDER}" --platform="${TARGET_OS}/${TARGET_ARCH}"
docker buildx build -t "${TARGET_REPO}" -f "${DOCKERFILE}" \
--build-arg CATTLE_RANCHER_WEBHOOK_VERSION="${CATTLE_RANCHER_WEBHOOK_VERSION}" \
--build-arg CATTLE_CSP_ADAPTER_MIN_VERSION="${CATTLE_CSP_ADAPTER_MIN_VERSION}" \
--build-arg CATTLE_FLEET_VERSION="${CATTLE_FLEET_VERSION}" \
--build-arg ARCH="${TARGET_ARCH}" \
"${PACKAGE_FOLDER}" --platform="${TARGET_OS}/${TARGET_ARCH}"
69 changes: 69 additions & 0 deletions docs/build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## Build and package configuration

Build variables should be defined in a single file,
so that anyone who wants to build Rancher needs to only edit this file to change configuration and dependency versions.

Rancher relies on various subcomponents, such as the webhook.
These typically need to have set versions for Rancher to build and run properly.
Build variables can be used in different places and supplied to the applications in a variety of ways,
including as environment variables in Dockerfiles, constants in Go code, and so on.

The [build.yaml](../build.yaml) file is the single source of truth. It lists all values by name and value.
Changes to it should be committed to source control.

### Update an existing value

Edit the [build.yaml](../build.yaml) file and update the desired value. Run `go generate`. Commit any changes to source
control. To test locally, re-build Rancher with `make build` or re-package it with `make package`.

### Add a new value

To add a new value, do the following once.

Add it to [build.yaml](../build.yaml). For example:

```
webhookVersion: 2.0.6+up0.3.6-rc1
```

Then update the [export-config](../scripts/export-config) script.

```
CATTLE_RANCHER_WEBHOOK_VERSION=$(yq -e '.webhookVersion' "$file")
export CATTLE_RANCHER_WEBHOOK_VERSION
```

Run `go generate` from the root of the repo.

Now you can refer to the value wherever you need it.

#### Refer to the new value

If a new configuration value is an environment variable for a Dockerfile, capture it as an `ARG` and `ENV`. For example:

```
ARG CATTLE_FLEET_VERSION
ENV CATTLE_FLEET_VERSION=$CATTLE_FLEET_VERSION
```

Then pass it as via `docker build --build-arg MYVAR="$MYVAR" ...`

If a new configuration value is a regular string outside Dockerfiles, refer to the corresponding constant found in the
generated Go [file](../pkg/buildconfig/constants.go). For example:

```NewSetting("shell-image", buildconfig.DefaultShellVersion)```

The following are examples of files that often refer to newly added configuration values:

- [build-server](../scripts/build-server)
- [build-agent](../scripts/build-agent)
- [build-local.sh](../dev-scripts/build-local.sh)
- [Dockerfile](../package/Dockerfile)
- [Dockerfile.agent](../package/Dockerfile.agent)
- [pkg/settings/setting.go](../pkg/settings/setting.go)

### The build.yaml file

It's better to follow the standard Kubernetes convention of preferring camelCase keys in the YAML file.

The exported resulting environment variables should be like standard ENV_VARS.
1 change: 1 addition & 0 deletions generate.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:generate go run pkg/codegen/buildconfig/writer.go pkg/codegen/buildconfig/main.go
//go:generate go run pkg/codegen/generator/cleanup/main.go
//go:generate go run pkg/codegen/main.go
//go:generate scripts/build-crds
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ require (
golang.org/x/net v0.14.0
golang.org/x/oauth2 v0.11.0
golang.org/x/sync v0.3.0
golang.org/x/text v0.12.0 // indirect
golang.org/x/text v0.12.0
golang.org/x/tools v0.12.0 // indirect
google.golang.org/api v0.138.0
google.golang.org/grpc v1.57.0
Expand Down Expand Up @@ -402,7 +402,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gopkg.in/yaml.v3 v3.0.1
k8s.io/cluster-bootstrap v0.27.2 // indirect
k8s.io/code-generator v0.27.5 // indirect
k8s.io/component-base v0.27.6 // indirect
Expand Down
9 changes: 6 additions & 3 deletions package/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ ENV CATTLE_SYSTEM_UPGRADE_CONTROLLER_CHART_VERSION 103.0.0+up0.6.0
# System charts minimal version
# Deprecated in favor of CATTLE_FLEET_VERSION.
ENV CATTLE_FLEET_MIN_VERSION=""
ENV CATTLE_FLEET_VERSION=103.1.0+up0.9.0
ENV CATTLE_RANCHER_WEBHOOK_VERSION=103.0.1+up0.4.2
ENV CATTLE_CSP_ADAPTER_MIN_VERSION=103.0.0+up3.0.0
ARG CATTLE_FLEET_VERSION
ENV CATTLE_FLEET_VERSION=$CATTLE_FLEET_VERSION
ARG CATTLE_RANCHER_WEBHOOK_VERSION
ENV CATTLE_RANCHER_WEBHOOK_VERSION=$CATTLE_RANCHER_WEBHOOK_VERSION
ARG CATTLE_CSP_ADAPTER_MIN_VERSION
ENV CATTLE_CSP_ADAPTER_MIN_VERSION=$CATTLE_CSP_ADAPTER_MIN_VERSION

RUN mkdir -p /var/lib/rancher-data/local-catalogs/system-library && \
mkdir -p /var/lib/rancher-data/local-catalogs/library && \
Expand Down
3 changes: 2 additions & 1 deletion package/Dockerfile.agent
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ ARG VERSION=dev
LABEL io.cattle.agent true
ENV AGENT_IMAGE rancher/rancher-agent:${VERSION}
# For now, this value needs to be manually synced with the one in the main Dockerfile. This pins downstream webhook's version.
ENV CATTLE_RANCHER_WEBHOOK_VERSION=103.0.1+up0.4.2
ARG CATTLE_RANCHER_WEBHOOK_VERSION
ENV CATTLE_RANCHER_WEBHOOK_VERSION=$CATTLE_RANCHER_WEBHOOK_VERSION
ENV SSL_CERT_DIR /etc/kubernetes/ssl/certs
COPY --from=rancher /var/lib/rancher-data /var/lib/rancher-data
COPY --from=rancher /usr/bin/tini /usr/bin/
Expand Down
10 changes: 10 additions & 0 deletions pkg/buildconfig/constants.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions pkg/codegen/buildconfig/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// This program generates a Go file containing a set of exported constants that represent
// configuration variables of Rancher at build-time.
package main

import (
"fmt"
"os"
"text/template"
)

func main() {
if err := generateGoConstantsFile(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func generateGoConstantsFile() error {
in, err := os.OpenFile("build.yaml", os.O_RDONLY, 0644)
if err != nil {
return err
}
out, err := os.OpenFile("pkg/buildconfig/constants.go", os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
return err
}
const raw = `// Code generated by pkg/codegen/config/main.go. DO NOT EDIT.
// Package buildconfig contains a set of exported constants that represent configuration variables of Rancher at build-time.
package buildconfig
const (
{{ . }})
`
tmpl, err := template.New("").Parse(raw)
if err != nil {
return err
}
writer := GoConstantsWriter{
Tmpl: tmpl,
Input: in,
Output: out,
}
return writer.Run()
}
97 changes: 97 additions & 0 deletions pkg/codegen/buildconfig/writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package main

import (
"bytes"
"errors"
"fmt"
"go/format"
"io"
"sort"
"strings"
"text/template"

"golang.org/x/text/cases"
"golang.org/x/text/language"
"gopkg.in/yaml.v3"
)

type GoConstantsWriter struct {
Input io.Reader
Output io.Writer
Tmpl *template.Template
buf []byte
cfg map[string]string
}

// Run loads YAML data from the pre-configured Input source, processes it, and outputs a template with formatted
// Go constants in the pre-configured Output source. This method can only be run once, since the Input source gets fully read.
func (f *GoConstantsWriter) Run() error {
if err := f.load(); err != nil {
return err
}
if err := f.process(); err != nil {
return err
}
if err := f.write(); err != nil {
return err
}
return nil
}

func (f *GoConstantsWriter) load() error {
if f.Input == nil {
return errors.New("nil input")
}
b, err := io.ReadAll(f.Input)
if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}
if len(b) == 0 {
return errors.New("nothing was read")
}
if err := yaml.Unmarshal(b, &f.cfg); err != nil {
return fmt.Errorf("failed to unmarshal raw YAML from input: %w", err)
}
return nil
}

func (f *GoConstantsWriter) process() error {
if f.Tmpl == nil {
return errors.New("nil template")
}
// This sorts the keys alphabetically to process the map in a fixed order.
keys := make([]string, 0, len(f.cfg))
for k := range f.cfg {
keys = append(keys, k)
}
sort.Strings(keys)

capitalize := cases.Title(language.English, cases.NoLower)
var builder strings.Builder
for _, k := range keys {
v := f.cfg[k]
// Capitalize the key to make the constant exported in the generated Go file.
k = capitalize.String(k)
s := fmt.Sprintf("\t%s = %q\n", k, v)
builder.WriteString(s)
}

buf := new(bytes.Buffer)
if err := f.Tmpl.Execute(buf, builder.String()); err != nil {
return err
}
f.buf = buf.Bytes()
return nil
}

func (f *GoConstantsWriter) write() error {
if f.Output == nil {
return errors.New("nil output")
}
formatted, err := format.Source(f.buf)
if err != nil {
return err
}
_, err = f.Output.Write(formatted)
return err
}
Loading

0 comments on commit 0cf1275

Please sign in to comment.