Repository: grafana/tanka
Pull request #967 (2023-12-05 15:56:05)

extract: Don't crash when the error is not an `ErrorPrimitiveReached`
When there's an invalid Kubernetes object, we can get a `*manifest.SchemaError` here, for example. We currently panic, but instead we should return the error so it can be displayed properly.

Closes: #960 

iainlane: See the first commit - new test fails there and then passes with the second one

Patch:
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index b0fbe9c6..061cf2b9 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -76,16 +76,19 @@ jobs:
           outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
 
       - name: Export digest
+        id: digest
         if: github.event_name != 'pull_request'
         run: |
           mkdir -p /tmp/digests
           digest="${{ steps.build.outputs.digest }}"
           touch "/tmp/digests/${digest#sha256:}"          
+          echo "artifact_name=digests-${{ matrix.platform }}" | sed -e 's/\//-/g' >> "$GITHUB_OUTPUT"
+
       - name: Upload digest
         if: github.event_name != 'pull_request'
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
-          name: digests
+          name: ${{ steps.digest.outputs.artifact_name }}
           path: /tmp/digests/*
           if-no-files-found: error
           retention-days: 1
@@ -96,11 +99,23 @@ jobs:
     needs: 
       - build
     steps:
-      - name: Download digests
-        uses: actions/download-artifact@v3
+      - name: Download digests (linux/amd64)
+        uses: actions/download-artifact@v4
+        with:
+          name: digests-linux-amd64
+          path: /tmp/digests-linux-amd64
+
+      - name: Download digests (linux/arm64)
+        uses: actions/download-artifact@v4
         with:
-          name: digests
-          path: /tmp/digests
+          name: digests-linux-arm64
+          path: /tmp/digests-linux-arm64
+
+      - name: Merge digests
+        run: |
+          mkdir -p /tmp/digests
+          cp /tmp/digests-linux-amd64/* /tmp/digests/
+          cp /tmp/digests-linux-arm64/* /tmp/digests/
 
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v3
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4b62a4ff..d374c8eb 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,7 +15,7 @@ jobs:
       - uses: actions/checkout@v4
         with:
           fetch-tags: true
-      - uses: actions/setup-go@v4
+      - uses: actions/setup-go@v5
         with:
           go-version: '1.20'
       - run: make cross
diff --git a/Dockerfile b/Dockerfile
index 24507ca8..b2195fed 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 # download kubectl
-FROM golang:1.21.4-alpine as kubectl
+FROM golang:1.21.5-alpine as kubectl
 RUN apk add --no-cache curl
 RUN export VERSION=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt) &&\
     export OS=$(go env GOOS) && \
@@ -8,7 +8,7 @@ RUN export VERSION=$(curl -s https://storage.googleapis.com/kubernetes-release/r
     chmod +x /usr/local/bin/kubectl
 
 # build jsonnet-bundler
-FROM golang:1.21.4-alpine as jb
+FROM golang:1.21.5-alpine as jb
 WORKDIR /tmp
 RUN apk add --no-cache git make bash &&\
     git clone https://github.com/jsonnet-bundler/jsonnet-bundler &&\
@@ -17,7 +17,7 @@ RUN apk add --no-cache git make bash &&\
     make static &&\
     mv _output/jb /usr/local/bin/jb
 
-FROM golang:1.21.4-alpine as helm
+FROM golang:1.21.5-alpine as helm
 WORKDIR /tmp/helm
 RUN apk add --no-cache jq curl
 RUN export TAG=$(curl --silent "https://api.github.com/repos/helm/helm/releases/latest" | jq -r .tag_name) &&\
@@ -26,7 +26,7 @@ RUN export TAG=$(curl --silent "https://api.github.com/repos/helm/helm/releases/
     curl -SL "https://get.helm.sh/helm-${TAG}-${OS}-${ARCH}.tar.gz" > helm.tgz && \
     tar -xvf helm.tgz --strip-components=1
 
-FROM golang:1.21.4-alpine as kustomize
+FROM golang:1.21.5-alpine as kustomize
 WORKDIR /tmp/kustomize
 RUN apk add --no-cache jq curl
 # Get the latest version of kustomize
@@ -39,7 +39,7 @@ RUN export TAG=$(curl --silent "https://api.github.com/repos/kubernetes-sigs/kus
     curl -SL "https://github.com/kubernetes-sigs/kustomize/releases/download/${TAG}/kustomize_${VERSION_TAG}_${OS}_${ARCH}.tar.gz" > kustomize.tgz && \
     tar -xvf kustomize.tgz
 
-FROM golang:1.21.4 as build
+FROM golang:1.21.5 as build
 WORKDIR /app
 COPY . .
 RUN make static
diff --git a/docs/docs/tutorial/refresher.mdx b/docs/docs/tutorial/refresher.mdx
index a737f1e3..7b0cc8f5 100644
--- a/docs/docs/tutorial/refresher.mdx
+++ b/docs/docs/tutorial/refresher.mdx
@@ -140,7 +140,7 @@ kubectl port-forward deployments/grafana 8080:3000
 ```
 
 Now go to http://localhost:8080 in your browser and login using `admin:admin`.
-Then navigate to `Configuration > Data Sources > Add data source`, choose
+Then navigate to `Connections > Data sources > Add new data source`, choose
 `Prometheus` as type and enter `http://prometheus:9090` as URL. Hit
 `Save & Test` which should yield a big green bar telling you everything is good.
 
diff --git a/pkg/process/extract.go b/pkg/process/extract.go
index a80b1e91..18799150 100644
--- a/pkg/process/extract.go
+++ b/pkg/process/extract.go
@@ -89,7 +89,11 @@ func walkObj(obj objx.Map, extracted map[string]manifest.Manifest, path trace) e
 		}
 		err := walkJSON(obj[key], extracted, path)
 		if err != nil {
-			return err.(ErrorPrimitiveReached).WithContainingObj(obj, manifestErr)
+			if err, ok := err.(ErrorPrimitiveReached); ok {
+				return err.WithContainingObj(obj, manifestErr)
+			}
+
+			return err
 		}
 	}
 


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7e10bbe0..cccee894 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,7 +13,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: actions/setup-go@v4
+      - uses: actions/setup-go@v5
         with:
           go-version: '1.20'
       - run: make lint
@@ -22,7 +22,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: actions/setup-go@v4
+      - uses: actions/setup-go@v5
         with:
           go-version: '1.20'
       - uses: azure/setup-helm@v3
@@ -36,7 +36,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: actions/setup-go@v4
+      - uses: actions/setup-go@v5
         with:
           go-version: '1.20'
       - run: make cross
diff --git a/pkg/tanka/export_test.go b/pkg/tanka/export_test.go
index ae9e4b8f..7bf000d8 100644
--- a/pkg/tanka/export_test.go
+++ b/pkg/tanka/export_test.go
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/grafana/tanka/pkg/jsonnet"
+	"github.com/grafana/tanka/pkg/kubernetes/manifest"
 	"github.com/rs/zerolog"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -142,6 +143,25 @@ func TestExportEnvironments(t *testing.T) {
 }`)
 }
 
+func TestExportEnvironmentsBroken(t *testing.T) {
+	tempDir := t.TempDir()
+	require.NoError(t, os.Chdir("testdata"))
+	defer func() { require.NoError(t, os.Chdir("..")) }()
+
+	// Find envs
+	envs, err := FindEnvs("test-export-envs-broken", FindOpts{Selector: labels.Everything()})
+	require.NoError(t, err)
+
+	// Export all envs
+	opts := &ExportEnvOpts{
+		Format:    "{{.metadata.namespace}}/{{.metadata.name}}",
+		Extension: "yaml",
+	}
+
+	var schemaError *manifest.SchemaError
+	require.ErrorAs(t, ExportEnvironments(envs, tempDir, opts), &schemaError)
+}
+
 func BenchmarkExportEnvironmentsWithReplaceEnvs(b *testing.B) {
 	zerolog.SetGlobalLevel(zerolog.Disabled)
 	tempDir := b.TempDir()
diff --git a/pkg/tanka/testdata/test-export-envs-broken/static-env/main.jsonnet b/pkg/tanka/testdata/test-export-envs-broken/static-env/main.jsonnet
new file mode 100644
index 00000000..76df07e0
--- /dev/null
+++ b/pkg/tanka/testdata/test-export-envs-broken/static-env/main.jsonnet
@@ -0,0 +1,17 @@
+{
+  deployment: {
+    apiVersion: 'apps/v1',
+    kind: 'Deployment',
+    metadata: {
+      name: 'foo',
+    },
+  },
+  service: {
+    apiVersion: 'v1',
+    kind: 'Service',
+    metadata: {
+      // Error, this should be a string
+      name: true,
+    },
+  },
+}
diff --git a/pkg/tanka/testdata/test-export-envs-broken/static-env/spec.json b/pkg/tanka/testdata/test-export-envs-broken/static-env/spec.json
new file mode 100644
index 00000000..52f9f830
--- /dev/null
+++ b/pkg/tanka/testdata/test-export-envs-broken/static-env/spec.json
@@ -0,0 +1,14 @@
+{
+  "apiVersion": "tanka.dev/v1alpha1",
+  "kind": "Environment",
+  "metadata": {
+    "name": "static",
+    "labels": {
+      "type": "static"
+    }
+  },
+  "spec": {
+    "apiServer": "https://localhost",
+    "namespace": "static"
+  }
+}