Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions commands/live/apply/cmdapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ import (
alphaprinterstable "github.com/kptdev/kpt/pkg/printer/table"
"github.com/kptdev/kpt/pkg/status"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes"
"k8s.io/kubectl/pkg/cmd/util"
"sigs.k8s.io/cli-utils/cmd/flagutils"
"sigs.k8s.io/cli-utils/pkg/apply"
Expand All @@ -54,6 +56,13 @@ func NewRunner(
applyRunner: runApply,
alpha: alpha,
}
r.namespaceChecker = func(namespace string) error {
clientset, err := factory.KubernetesClientSet()
if err != nil {
return err
}
return checkNamespaceExists(clientset, namespace)
}
c := &cobra.Command{
Use: "apply [PKG_PATH | -]",
RunE: r.runE,
Expand Down Expand Up @@ -124,6 +133,7 @@ type Runner struct {

applyRunner func(r *Runner, invInfo inventory.Info, objs []*unstructured.Unstructured,
dryRunStrategy common.DryRunStrategy) error
namespaceChecker func(namespace string) error
}

func (r *Runner) preRunE(cmd *cobra.Command, _ []string) error {
Expand Down Expand Up @@ -191,6 +201,12 @@ func (r *Runner) runE(c *cobra.Command, args []string) error {
return err
}

if !live.NamespaceInObjects(objs, inv.Namespace) {
Comment thread
Catalin-Stratulat-Ericsson marked this conversation as resolved.
if err := r.namespaceChecker(inv.Namespace); err != nil {
return err
}
}

invInfo, err := live.ToInventoryInfo(inv)
if err != nil {
return err
Expand Down Expand Up @@ -289,3 +305,14 @@ func runApply(r *Runner, invInfo inventory.Info, objs []*unstructured.Unstructur
}
return printer.Print(ch, dryRunStrategy, r.printStatusEvents)
}

func checkNamespaceExists(clientset kubernetes.Interface, namespace string) error {
if namespace == "" {
namespace = "default"
}
_, err := clientset.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return fmt.Errorf("inventory namespace %q does not exist", namespace)
}
return err
}
45 changes: 45 additions & 0 deletions commands/live/apply/cmdapply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,57 @@ import (
"github.com/kptdev/kpt/pkg/kptfile/kptfileutil"
"github.com/kptdev/kpt/pkg/printer/fake"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/cli-runtime/pkg/genericclioptions"
k8sfake "k8s.io/client-go/kubernetes/fake"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
)

func TestCheckNamespaceExistsWithClient(t *testing.T) {
testCases := map[string]struct {
namespace string
existingNs string
expectedErrMsg string
}{
"namespace exists": {
namespace: "my-ns",
existingNs: "my-ns",
},
"namespace does not exist": {
namespace: "missing-ns",
existingNs: "other-ns",
expectedErrMsg: `inventory namespace "missing-ns" does not exist`,
},
"empty namespace defaults to default and exists": {
namespace: "",
existingNs: "default",
},
"empty namespace defaults to default but default missing": {
namespace: "",
existingNs: "other-ns",
expectedErrMsg: `inventory namespace "default" does not exist`,
},
}

for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
clientset := k8sfake.NewSimpleClientset(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: tc.existingNs},
})
err := checkNamespaceExists(clientset, tc.namespace)
if tc.expectedErrMsg != "" {
assert.EqualError(t, err, tc.expectedErrMsg)
} else {
assert.NoError(t, err)
}
})
}
}

func TestCmd(t *testing.T) {
testCases := map[string]struct {
args []string
Expand Down Expand Up @@ -148,6 +192,7 @@ func TestCmd(t *testing.T) {

runner := NewRunner(fake.CtxWithDefaultPrinter(), tf, ioStreams, false)
runner.Command.SetArgs(tc.args)
runner.namespaceChecker = func(_ string) error { return nil }
Comment thread
OisinJohnston2005 marked this conversation as resolved.
runner.applyRunner = func(_ *Runner, inv inventory.Info,
_ []*unstructured.Unstructured, _ common.DryRunStrategy) error {
tc.applyCallbackFunc(t, runner, inv)
Expand Down
10 changes: 10 additions & 0 deletions pkg/live/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,16 @@ func validateInventory(inventory kptfilev1.Inventory) error {
return nil
}

// NamespaceInObjects return true if any object in objs is a Namespace with the given name
func NamespaceInObjects(objs []*unstructured.Unstructured, namespace string) bool {
for _, obj := range objs {
if obj.GetKind() == "Namespace" && obj.GetName() == namespace {
return true
}
}
return false
}

func generateInventoryObj(inv kptfilev1.Inventory) *unstructured.Unstructured {
// Create and return ResourceGroup custom resource as inventory object.

Expand Down