Skip to content

Commit

Permalink
yoke: ensure namespace exists before applying resources
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmdm committed Apr 30, 2024
1 parent a6657ae commit 8cee965
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 5 deletions.
1 change: 1 addition & 0 deletions cmd/yoke/cmd_takeoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func TakeOff(ctx context.Context, params TakeoffParams) error {
Release: params.Release,
Resources: resources,
FlightID: params.Flight.Path,
Namespace: params.Flight.Namespace,
Wasm: wasm,
SkipDryRun: params.SkipDryRun,
ForceConflicts: params.ForceConflicts,
Expand Down
31 changes: 31 additions & 0 deletions cmd/yoke/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/stretchr/testify/require"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
Expand Down Expand Up @@ -148,3 +149,33 @@ func TestReleaseOwnership(t *testing.T) {
`failed to validate ownership: conflict(s): resource "default.apps.v1.deployment.sample-app" is owned by release "foo"`,
)
}

func TestTakeoffWithNamespace(t *testing.T) {
rest, err := clientcmd.BuildConfigFromFlags("", home.Kubeconfig)
require.NoError(t, err)

client, err := kubernetes.NewForConfig(rest)
require.NoError(t, err)

_, err = client.CoreV1().Namespaces().Get(context.Background(), "test-ns", metav1.GetOptions{})
require.True(t, kerrors.IsNotFound(err))

settings := GlobalSettings{KubeConfigPath: home.Kubeconfig}

params := TakeoffParams{
Release: "foo",
GlobalSettings: settings,
Flight: TakeoffFlightParams{
Input: createBasicDeployment(t, "sample-app", "default"),
Namespace: "test-ns",
},
}

require.NoError(t, TakeOff(context.Background(), params))
defer func() {
require.NoError(t, Mayday(context.Background(), MaydayParams{Release: "foo", GlobalSettings: settings}))
}()

_, err = client.CoreV1().Namespaces().Get(context.Background(), "test-ns", metav1.GetOptions{})
require.NoError(t, err)
}
20 changes: 20 additions & 0 deletions internal/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,26 @@ func (client Client) DeleteRevisions(ctx context.Context, release string) error
Delete(ctx, releaseName(release), metav1.DeleteOptions{})
}

func (client Client) EnsureNamespace(ctx context.Context, namespace string) error {
defer internal.DebugTimer(ctx, "ensuring namespace")()

if _, err := client.clientset.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}); err != nil {
if !kerrors.IsNotFound(err) {
return err
}

if _, err := client.clientset.CoreV1().Namespaces().Create(
ctx,
&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}},
metav1.CreateOptions{},
); err != nil {
return fmt.Errorf("failed to create namespace: %w", err)
}
}

return nil
}

func IsNamespaced(resource dynamic.ResourceInterface) bool {
_, ok := resource.(interface{ Namespace(string) bool })
return ok
Expand Down
9 changes: 4 additions & 5 deletions internal/wasi/wasi.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ func Execute(ctx context.Context, params ExecParams) (output []byte, err error)
NewRuntimeConfig().
WithCloseOnContextDone(true)

// Create a new WebAssembly Runtime.
wasi := wazero.NewRuntimeWithConfig(ctx, cfg)
runtime := wazero.NewRuntimeWithConfig(ctx, cfg)
defer func() {
err = xerr.MultiErrFrom("", err, wasi.Close(ctx))
err = xerr.MultiErrFrom("", err, runtime.Close(ctx))
}()

wasi_snapshot_preview1.MustInstantiate(ctx, wasi)
wasi_snapshot_preview1.MustInstantiate(ctx, runtime)

var (
stdout bytes.Buffer
Expand All @@ -60,7 +59,7 @@ func Execute(ctx context.Context, params ExecParams) (output []byte, err error)
moduleCfg = moduleCfg.WithEnv(key, value)
}

if _, err := wasi.InstantiateWithConfig(ctx, params.Wasm, moduleCfg); err != nil {
if _, err := runtime.InstantiateWithConfig(ctx, params.Wasm, moduleCfg); err != nil {
details := stderr.String()
if details == "" {
details = "(no output captured on stderr)"
Expand Down
7 changes: 7 additions & 0 deletions pkg/yoke/yoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type TakeoffParams struct {
Release string
Resources []*unstructured.Unstructured
FlightID string
Namespace string
Wasm []byte
SkipDryRun bool
ForceConflicts bool
Expand All @@ -54,6 +55,12 @@ func (client Client) Takeoff(ctx context.Context, params TakeoffParams) error {
return fmt.Errorf("failed to validate ownership: %w", err)
}

if params.Namespace != "" {
if err := client.k8s.EnsureNamespace(ctx, params.Namespace); err != nil {
return fmt.Errorf("failed to ensure namespace: %w", err)
}
}

applyOpts := k8s.ApplyResourcesOpts{
SkipDryRun: params.SkipDryRun,
ForceConflicts: params.ForceConflicts,
Expand Down

0 comments on commit 8cee965

Please sign in to comment.