diff --git a/Dockerfile b/Dockerfile index ee2209063e..ac46663d10 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,9 @@ RUN set -x \ libseccomp-dev \ rsync \ py-pip \ - pigz + pigz \ + tar \ + yq # Dapper/Drone/CI environment FROM build AS dapper @@ -74,6 +76,7 @@ VOLUME /var/lib/rancher/k3s FROM build AS charts ARG CHART_REPO="https://rke2-charts.rancher.io" +ARG KUBERNETES_VERSION="" ARG CACHEBUST="cachebust" COPY charts/ /charts/ RUN echo ${CACHEBUST}>/dev/null diff --git a/charts/build-chart.sh b/charts/build-chart.sh index faea9ba2ee..0af43dd105 100755 --- a/charts/build-chart.sh +++ b/charts/build-chart.sh @@ -2,11 +2,34 @@ set -eux -o pipefail +: "${KUBERNETES_VERSION:=v0.0.0-0}" : "${CHART_FILE?required}" : "${CHART_NAME:="$(basename "${CHART_FILE%%.yaml}")"}" -: "${CHART_PACKAGE:="${CHART_NAME}"}" +: "${CHART_PACKAGE:="${CHART_NAME%%-crd}"}" +: "${TAR_OPTS:=--owner=0 --group=0 --mode=gou-s+r --numeric-owner --no-acls --no-selinux --no-xattrs}" : "${CHART_URL:="${CHART_REPO:="https://rke2-charts.rancher.io"}/assets/${CHART_PACKAGE}/${CHART_NAME}-${CHART_VERSION:="v0.0.0"}.tgz"}" -curl -fsSL "${CHART_URL}" -o "${CHART_TMP:=$(mktemp)}" +: "${CHART_TMP:=$(mktemp --suffix .tar.gz)}" +: "${YAML_TMP:=$(mktemp --suffix .yaml)}" + +cleanup() { + exit_code=$? + trap - EXIT INT + rm -rf ${CHART_TMP} ${CHART_TMP/tar.gz/tar} ${YAML_TMP} + exit ${exit_code} +} +trap cleanup EXIT INT + +curl -fsSL "${CHART_URL}" -o "${CHART_TMP}" +gunzip ${CHART_TMP} + +# Extract out Chart.yaml, inject a version requirement and bundle-id annotation, and delete/replace the one in the original tarball +tar -xOf ${CHART_TMP/.gz/} ${CHART_NAME}/Chart.yaml > ${YAML_TMP} +yq -i e ".kubeVersion = \">= ${KUBERNETES_VERSION}\" | .annotations.\"fleet.cattle.io/bundle-id\" = \"rke2\"" ${YAML_TMP} +tar --delete -b 8192 -f ${CHART_TMP/.gz/} ${CHART_NAME}/Chart.yaml +tar --transform="s|.*|${CHART_NAME}/Chart.yaml|" ${TAR_OPTS} -vrf ${CHART_TMP/.gz/} ${YAML_TMP} + +pigz -11 ${CHART_TMP/.gz/} + cat <<-EOF > "${CHART_FILE}" apiVersion: helm.cattle.io/v1 kind: HelmChart diff --git a/pkg/bootstrap/bootstrap.go b/pkg/bootstrap/bootstrap.go index 3fa4cf9248..5ea32ef6c6 100644 --- a/pkg/bootstrap/bootstrap.go +++ b/pkg/bootstrap/bootstrap.go @@ -1,9 +1,11 @@ package bootstrap import ( + "bytes" "crypto/sha256" "encoding/hex" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -293,13 +295,13 @@ func setChartValues(manifestsDir string, nodeConfig *daemonconfig.Node, cfg cmds // If the file cannot be decoded as a HelmChart, it is silently skipped. Any other IO error is considered // a failure. func rewriteChart(fileName string, info os.FileInfo, chartValues map[string]string, serializer *json.Serializer) error { - bytes, err := ioutil.ReadFile(fileName) + b, err := ioutil.ReadFile(fileName) if err != nil { return errors.Wrapf(err, "Failed to read manifest %s", fileName) } // Ignore manifest if it cannot be decoded - obj, _, err := serializer.Decode(bytes, nil, nil) + obj, _, err := serializer.Decode(b, nil, nil) if err != nil { logrus.Debugf("Failed to decode manifest %s: %s", fileName, err) return nil @@ -319,21 +321,37 @@ func rewriteChart(fileName string, info os.FileInfo, chartValues map[string]stri chart.Spec.Set = map[string]intstr.IntOrString{} } + var changed bool for k, v := range chartValues { - chart.Spec.Set[k] = intstr.FromString(v) + val := intstr.FromString(v) + if cur, ok := chart.Spec.Set[k]; ok { + curBytes, _ := cur.MarshalJSON() + newBytes, _ := val.MarshalJSON() + if bytes.Equal(curBytes, newBytes) { + continue + } + } + changed = true + chart.Spec.Set[k] = val } - f, err := os.OpenFile(fileName, os.O_RDWR|os.O_TRUNC, info.Mode()) - if err != nil { - return errors.Wrapf(err, "Unable to open HelmChart %s", fileName) + if !changed { + logrus.Infof("No cluster configuration value changes necessary for HelmChart %s", fileName) + return nil } - if err := serializer.Encode(chart, f); err != nil { - _ = f.Close() + var buf bytes.Buffer + if err := serializer.Encode(chart, &buf); err != nil { return errors.Wrapf(err, "Failed to serialize modified HelmChart %s", fileName) } - if err := f.Close(); err != nil { + f, err := os.OpenFile(fileName, os.O_RDWR|os.O_TRUNC, info.Mode()) + if err != nil { + return errors.Wrapf(err, "Unable to open HelmChart %s", fileName) + } + defer f.Close() + + if _, err := io.Copy(f, &buf); err != nil { return errors.Wrapf(err, "Failed to write modified HelmChart %s", fileName) }