diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 89a8cf3a..e3afbed0 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -11,7 +11,7 @@ permissions: contents: read jobs: - kubernetes: + k8s-modules: runs-on: ubuntu-latest services: registry: @@ -62,3 +62,38 @@ jobs: - name: Uninstall module run: | timoni -n test delete nginx --wait + + k8s-bundles: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version: 1.22.x + cache-dependency-path: | + **/go.sum + **/go.mod + - name: Setup Kubernetes + uses: helm/kind-action@99576bfa6ddf9a8e612d83b513da5a75875caced # v1.9.0 + with: + version: v0.22.0 + cluster_name: kind + - name: Install + run: make install + - name: Vet bundle with local module + run: | + timoni bundle vet -f hack/tests/bundle_local.cue + - name: Build bundle with local module + run: | + timoni bundle build -f hack/tests/bundle_local.cue + - name: Apply bundle with local module + run: | + timoni bundle apply -f hack/tests/bundle_local.cue + - name: Inspect bundle + run: | + timoni bundle status local-test + - name: Delete bundle + run: | + timoni bundle delete local-test diff --git a/cmd/timoni/bundle_build_test.go b/cmd/timoni/bundle_build_test.go index a5c01cb2..1d7a5ce6 100644 --- a/cmd/timoni/bundle_build_test.go +++ b/cmd/timoni/bundle_build_test.go @@ -10,6 +10,8 @@ import ( ssautil "github.com/fluxcd/pkg/ssa/utils" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/stefanprodan/timoni/internal/engine" ) func Test_BundleBuild(t *testing.T) { @@ -140,6 +142,56 @@ bundle: }) } +func Test_BundleBuild_LocalModule(t *testing.T) { + g := NewWithT(t) + + modPath := "testdata/module" + namespace := rnd("my-namespace", 5) + + bundleCue := fmt.Sprintf(` +bundle: { + apiVersion: "v1alpha1" + name: "my-bundle" + instances: { + backend: { + module: { + url: "file://%[1]s" + } + namespace: "%[2]s" + values: client: enabled: true + } + } +} +`, modPath, namespace) + + wd := t.TempDir() + cuePath := filepath.Join(wd, "bundle.cue") + g.Expect(os.WriteFile(cuePath, []byte(bundleCue), 0644)).ToNot(HaveOccurred()) + + err := engine.CopyModule(modPath, filepath.Join(wd, modPath)) + g.Expect(err).ToNot(HaveOccurred()) + + output, err := executeCommand(fmt.Sprintf( + "bundle build -f %s -p main", + cuePath, + )) + g.Expect(err).ToNot(HaveOccurred()) + + objects, err := ssautil.ReadObjects(strings.NewReader(output)) + g.Expect(err).ToNot(HaveOccurred()) + + backendClientCm, err := getObjectByName(objects, "backend-server") + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(backendClientCm.GetKind()).To(BeEquivalentTo("ConfigMap")) + g.Expect(backendClientCm.GetNamespace()).To(ContainSubstring(namespace)) + + host, found, err := unstructured.NestedString(backendClientCm.Object, "data", "hostname") + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(found).To(BeTrue()) + g.Expect(host).To(ContainSubstring("example.internal")) + +} + func Test_BundleBuild_Runtime(t *testing.T) { g := NewWithT(t) diff --git a/hack/tests/bundle_local.cue b/hack/tests/bundle_local.cue new file mode 100644 index 00000000..87b2dbd8 --- /dev/null +++ b/hack/tests/bundle_local.cue @@ -0,0 +1,18 @@ +bundle: { + apiVersion: "v1alpha1" + name: "local-test" + instances: { + ngnix: { + module: { + url: "file://../../blueprints/starter" + } + namespace: "nginx" + values: { + resources: limits: { + cpu: "100m" + memory: "128Mi" + } + } + } + } +} diff --git a/internal/engine/bundle_builder.go b/internal/engine/bundle_builder.go index c5475ace..0868ae8e 100644 --- a/internal/engine/bundle_builder.go +++ b/internal/engine/bundle_builder.go @@ -165,7 +165,8 @@ func (b *BundleBuilder) getInstanceUrl(v cue.Value) string { source = origin } url = filepath.Clean(filepath.Join(filepath.Dir(source), path)) - url = "file://" + path // re-add prefix + url = "file://" + url // re-add prefix + } return url } diff --git a/internal/engine/fetcher/fetcher.go b/internal/engine/fetcher/fetcher.go index 747b3e63..78c3264d 100644 --- a/internal/engine/fetcher/fetcher.go +++ b/internal/engine/fetcher/fetcher.go @@ -47,7 +47,7 @@ type Options struct { DefaultLocal bool } -// NewFetcher is a factory function that creates a new Fetcher based on the provided options. +// New is a factory function that creates a new Fetcher based on the provided options. // If you know the type of fetcher you want to create, prefer using the specific factory function. func New(ctx context.Context, opts Options) (Fetcher, error) { switch { diff --git a/internal/engine/fetcher/local.go b/internal/engine/fetcher/local.go index 1d2e672e..2429a2f7 100644 --- a/internal/engine/fetcher/local.go +++ b/internal/engine/fetcher/local.go @@ -21,6 +21,7 @@ import ( "os" "path" "path/filepath" + "strings" apiv1 "github.com/stefanprodan/timoni/api/v1alpha1" "github.com/stefanprodan/timoni/internal/engine" @@ -34,6 +35,7 @@ type Local struct { // NewLocal creates a local Fetcher for the given module. func NewLocal(src, dst string) *Local { + src = strings.TrimPrefix(src, apiv1.LocalPrefix) requiredFiles := []string{ path.Join(src, "cue.mod", "module.cue"), path.Join(src, "timoni.cue"),