Skip to content

Commit

Permalink
Install RG CRD with kpt live apply by default unless dry-run (#2154)
Browse files Browse the repository at this point in the history
* Install RG CRD with kpt live apply by default unless dry-run

* Fixed failing e2e test
  • Loading branch information
mortent committed Jun 7, 2021
1 parent 07d0269 commit ad87e13
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 15 deletions.
11 changes: 2 additions & 9 deletions e2e/live/end-to-end-test.sh
Expand Up @@ -430,16 +430,9 @@ ${BIN_DIR}/kpt live apply --dry-run e2e/live/testdata/rg-test-case-1a > $OUTPUT_
assertContains "Error: The ResourceGroup CRD was not found in the cluster. Please install it either by using the '--install-resource-group' flag or the 'kpt live install-resource-group' command."
printResult

# Test: Apply without ResourceGroup CRD installation fails
echo "[ResourceGroup] Testing basic apply without ResourceGroup inventory CRD"
echo "kpt live apply e2e/live/testdata/rg-test-case-1a"
${BIN_DIR}/kpt live apply e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status 2>&1
assertContains "Error: The ResourceGroup CRD was not found in the cluster. Please install it either by using the '--install-resource-group' flag or the 'kpt live install-resource-group' command."
printResult

# Test: Apply forcing ResourceGroup CRD installation succeeds
echo "[ResourceGroup] Testing create inventory CRD before basic apply"
echo "kpt live apply --install-resource-group e2e/live/testdata/rg-test-case-1a"
echo "kpt live apply e2e/live/testdata/rg-test-case-1a"
${BIN_DIR}/kpt live apply --install-resource-group e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status 2>&1
assertContains "namespace/rg-test-namespace"
assertContains "pod/pod-a created"
Expand Down Expand Up @@ -662,7 +655,7 @@ wait 2

# Attempt to apply two ConfigMaps: one in the default namespace (fails), and one
# in the "rbac-error" namespace (succeeds).
${BIN_DIR}/kpt live apply e2e/live/testdata/rbac-error-step-2 > $OUTPUT_DIR/status
${BIN_DIR}/kpt live apply --install-resource-group=false e2e/live/testdata/rbac-error-step-2 > $OUTPUT_DIR/status
assertRGInventory "rbac-error" "1"
assertContains "configmap/error-config-map apply failed"
assertContains "configmap/valid-config-map created"
Expand Down
28 changes: 22 additions & 6 deletions internal/cmdapply/cmdapply.go
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/GoogleContainerTools/kpt/thirdparty/cli-utils/printers"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/cli-runtime/pkg/genericclioptions"
"sigs.k8s.io/cli-utils/pkg/apply"
"sigs.k8s.io/cli-utils/pkg/common"
Expand All @@ -37,10 +38,11 @@ import (
func NewRunner(ctx context.Context, provider provider.Provider,
ioStreams genericclioptions.IOStreams) *Runner {
r := &Runner{
ctx: ctx,
Applier: apply.NewApplier(provider),
provider: provider,
ioStreams: ioStreams,
ctx: ctx,
Applier: apply.NewApplier(provider),
provider: provider,
ioStreams: ioStreams,
applyRunner: runApply,
}
c := &cobra.Command{
Use: "apply [PKG_PATH | -]",
Expand Down Expand Up @@ -68,7 +70,7 @@ func NewRunner(ctx context.Context, provider provider.Provider,
c.Flags().StringVar(&r.inventoryPolicyString, flagutils.InventoryPolicyFlag, flagutils.InventoryPolicyStrict,
"It determines the behavior when the resources don't belong to current inventory. Available options "+
fmt.Sprintf("%q and %q.", flagutils.InventoryPolicyStrict, flagutils.InventoryPolicyAdopt))
c.Flags().BoolVar(&r.installCRD, "install-resource-group", false,
c.Flags().BoolVar(&r.installCRD, "install-resource-group", true,
"If true, install the inventory ResourceGroup CRD before applying.")
c.Flags().BoolVar(&r.dryRun, "dry-run", false,
"dry-run apply for the resources in the package.")
Expand Down Expand Up @@ -101,9 +103,12 @@ type Runner struct {

inventoryPolicy inventory.InventoryPolicy
prunePropPolicy v1.DeletionPropagation

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

func (r *Runner) preRunE(_ *cobra.Command, _ []string) error {
func (r *Runner) preRunE(cmd *cobra.Command, _ []string) error {
var err error
r.prunePropPolicy, err = flagutils.ConvertPropagationPolicy(r.prunePropagationPolicyString)
if err != nil {
Expand All @@ -119,6 +124,12 @@ func (r *Runner) preRunE(_ *cobra.Command, _ []string) error {
return fmt.Errorf("unknown output type %q", r.output)
}

// We default the install-resource-group flag to false if we are doing
// dry-run, unless the user has explicitly used the install-resource-group flag.
if r.dryRun && !cmd.Flags().Changed("install-resource-group") {
r.installCRD = false
}

if !r.installCRD {
err := cmdutil.VerifyResourceGroupCRD(r.provider.Factory())
if err != nil {
Expand Down Expand Up @@ -165,6 +176,11 @@ func (r *Runner) runE(c *cobra.Command, args []string) error {
}
}

return r.applyRunner(r, invInfo, objs, dryRunStrategy)
}

func runApply(r *Runner, invInfo inventory.InventoryInfo, objs []*unstructured.Unstructured,
dryRunStrategy common.DryRunStrategy) error {
if r.installCRD {
err := cmdutil.InstallResourceGroupCRD(r.ctx, r.provider.Factory())
if err != nil {
Expand Down
162 changes: 162 additions & 0 deletions internal/cmdapply/cmdapply_test.go
@@ -0,0 +1,162 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmdapply

import (
"path/filepath"
"testing"

"github.com/GoogleContainerTools/kpt/internal/printer/fake"
"github.com/GoogleContainerTools/kpt/internal/testutil"
kptfilev1alpha2 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1alpha2"
"github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil"
"github.com/GoogleContainerTools/kpt/pkg/live"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
)

func TestCmd(t *testing.T) {
testCases := map[string]struct {
args []string
namespace string
inventory *kptfilev1alpha2.Inventory
applyCallbackFunc func(*testing.T, *Runner, inventory.InventoryInfo)
expectedErrorMsg string
}{
"invalid inventory policy": {
args: []string{
"--inventory-policy", "noSuchPolicy",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, _ *Runner, _ inventory.InventoryInfo) {
t.FailNow()
},
expectedErrorMsg: "inventory policy must be one of strict, adopt",
},
"invalid output format": {
args: []string{
"--output", "foo",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, _ *Runner, _ inventory.InventoryInfo) {
t.FailNow()
},
expectedErrorMsg: "unknown output type \"foo\"",
},
"fetches the correct inventory information from the Kptfile": {
args: []string{
"--inventory-policy", "adopt",
"--output", "events",
},
inventory: &kptfilev1alpha2.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, _ *Runner, inv inventory.InventoryInfo) {
assert.Equal(t, "my-ns", inv.Namespace())
assert.Equal(t, "my-name", inv.Name())
assert.Equal(t, "my-inv-id", inv.ID())
},
},
"install-resource-group flag defaults to true": {
args: []string{},
inventory: &kptfilev1alpha2.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, r *Runner, _ inventory.InventoryInfo) {
assert.True(t, r.installCRD)
},
},
"install-resource-group flag defaults to false when dry-run": {
args: []string{
"--dry-run",
},
inventory: &kptfilev1alpha2.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, r *Runner, _ inventory.InventoryInfo) {
assert.True(t, r.dryRun)
assert.False(t, r.installCRD)
},
expectedErrorMsg: "type ResourceGroup not found",
},
"install-resource-group flag remains true with dry-run if explicitly set": {
args: []string{
"--dry-run",
"--install-resource-group",
},
inventory: &kptfilev1alpha2.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
},
namespace: "testns",
applyCallbackFunc: func(t *testing.T, r *Runner, _ inventory.InventoryInfo) {
assert.True(t, r.dryRun)
assert.True(t, r.installCRD)
},
},
}

for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
tf := cmdtesting.NewTestFactory().WithNamespace(tc.namespace)
defer tf.Cleanup()
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams() //nolint:dogsled

w, clean := testutil.SetupWorkspace(t)
defer clean()
kf := kptfileutil.DefaultKptfile(filepath.Base(w.WorkspaceDirectory))
kf.Inventory = tc.inventory
testutil.AddKptfileToWorkspace(t, w, kf)

revert := testutil.Chdir(t, w.WorkspaceDirectory)
defer revert()

rgProvider := live.NewResourceGroupProvider(tf)

runner := NewRunner(fake.CtxWithNilPrinter(), rgProvider, ioStreams)
runner.Command.SetArgs(tc.args)
runner.applyRunner = func(_ *Runner, inv inventory.InventoryInfo,
_ []*unstructured.Unstructured, _ common.DryRunStrategy) error {
tc.applyCallbackFunc(t, runner, inv)
return nil
}
err := runner.Command.Execute()

// Check if there should be an error
if tc.expectedErrorMsg != "" {
if !assert.Error(t, err) {
t.FailNow()
}
assert.Contains(t, err.Error(), tc.expectedErrorMsg)
return
}
assert.NoError(t, err)
})
}
}

0 comments on commit ad87e13

Please sign in to comment.