Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kn export defect to honor mode #1212

Merged
merged 5 commits into from
Mar 4, 2021
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
68 changes: 35 additions & 33 deletions pkg/kn/commands/service/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/spf13/cobra"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"

Expand Down Expand Up @@ -64,6 +65,11 @@ var IgnoredRevisionLabels = []string{
"serving.knative.dev/serviceUID",
}

const (
ModeReplay = "replay"
ModeExport = "export"
)

// NewServiceExportCommand returns a new command for exporting a service.
func NewServiceExportCommand(p *commands.KnParams) *cobra.Command {

Expand Down Expand Up @@ -129,35 +135,25 @@ func exportService(cmd *cobra.Command, service *servingv1.Service, client client
return err
}

if !withRevisions {
return printer.PrintObj(exportLatestService(service.DeepCopy(), false), cmd.OutOrStdout())
}

mode, err := cmd.Flags().GetString("mode")
if err != nil {
return err
}

switch mode {
case "replay":
svcList, err := exportServiceListForReplay(service.DeepCopy(), client)
if mode == ModeReplay {
svcList, err := exportServiceListForReplay(service.DeepCopy(), client, withRevisions)
if err != nil {
return err
}
return printer.PrintObj(svcList, cmd.OutOrStdout())
case "export":
knExport, err := exportForKNImport(service.DeepCopy(), client)
if err != nil {
return err
}
//print kn export
if err := printer.PrintObj(knExport, cmd.OutOrStdout()); err != nil {
return err
}
default:
return errors.New("'kn service export --with-revisions' requires a mode, please specify one of replay|export")
}
return nil
// default is export mode
knExport, err := exportForKNImport(service.DeepCopy(), client, withRevisions)
if err != nil {
return err
}
//print kn export
return printer.PrintObj(knExport, cmd.OutOrStdout())
}

func exportLatestService(latestSvc *servingv1.Service, withRoutes bool) *servingv1.Service {
Expand Down Expand Up @@ -223,14 +219,17 @@ func constructServiceFromRevision(latestSvc *servingv1.Service, revision *servin
return exportedSvc
}

func exportServiceListForReplay(latestSvc *servingv1.Service, client clientservingv1.KnServingClient) (*servingv1.ServiceList, error) {
func exportServiceListForReplay(latestSvc *servingv1.Service, client clientservingv1.KnServingClient, withRevisions bool) (runtime.Object, error) {
if !withRevisions {
return exportLatestService(latestSvc, false), nil
}
var exportedSvcItems []servingv1.Service

revisionList, revsMap, err := getRevisionsToExport(latestSvc, client)
if err != nil {
return nil, err
}

var exportedSvcItems []servingv1.Service

for _, revision := range revisionList.Items {
//construct service only for active revisions
if revsMap[revision.ObjectMeta.Name] && revision.ObjectMeta.Name != latestSvc.Spec.Template.ObjectMeta.Name {
Expand All @@ -253,19 +252,22 @@ func exportServiceListForReplay(latestSvc *servingv1.Service, client clientservi
return exportedSvcList, nil
}

func exportForKNImport(latestSvc *servingv1.Service, client clientservingv1.KnServingClient) (*clientv1alpha1.Export, error) {
revisionList, revsMap, err := getRevisionsToExport(latestSvc, client)
if err != nil {
return nil, err
}

func exportForKNImport(latestSvc *servingv1.Service, client clientservingv1.KnServingClient, withRevisions bool) (*clientv1alpha1.Export, error) {
var exportedRevItems []servingv1.Revision
revisionHistoryCount := 0
if withRevisions {
revisionList, revsMap, err := getRevisionsToExport(latestSvc, client)
if err != nil {
return nil, err
}

for _, revision := range revisionList.Items {
//append only active revisions, no latest revision
if revsMap[revision.ObjectMeta.Name] && revision.ObjectMeta.Name != latestSvc.Spec.Template.ObjectMeta.Name {
exportedRevItems = append(exportedRevItems, exportRevision(revision.DeepCopy()))
for _, revision := range revisionList.Items {
//append only active revisions, no latest revision
if revsMap[revision.ObjectMeta.Name] && revision.ObjectMeta.Name != latestSvc.Spec.Template.ObjectMeta.Name {
exportedRevItems = append(exportedRevItems, exportRevision(revision.DeepCopy()))
}
}
revisionHistoryCount = len(revisionList.Items)
}

typeMeta := metav1.TypeMeta{
Expand All @@ -275,7 +277,7 @@ func exportForKNImport(latestSvc *servingv1.Service, client clientservingv1.KnSe
knExport := &clientv1alpha1.Export{
TypeMeta: typeMeta,
Spec: clientv1alpha1.ExportSpec{
Service: *(exportLatestService(latestSvc, len(revisionList.Items) > 1)),
Service: *(exportLatestService(latestSvc, revisionHistoryCount > 1)),
Revisions: exportedRevItems,
},
}
Expand Down
33 changes: 24 additions & 9 deletions pkg/kn/commands/service/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ func TestServiceExportError(t *testing.T) {

_, err := executeServiceExportCommand(t, tc, "export", tc.latestSvc.ObjectMeta.Name)
assert.Error(t, err, "'kn service export' requires output format")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a simple test verifying no latest revision in export?


_, err = executeServiceExportCommand(t, tc, "export", tc.latestSvc.ObjectMeta.Name, "--with-revisions", "-o", "json")
assert.Error(t, err, "'kn service export --with-revisions' requires a mode, please specify one of replay|export")

_, err = executeServiceExportCommand(t, tc, "export", tc.latestSvc.ObjectMeta.Name, "--with-revisions", "--mode", "k8s", "-o", "yaml")
assert.Error(t, err, "'kn service export --with-revisions' requires a mode, please specify one of replay|export")
}

func TestServiceExport(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have a similar set of tests for service export --mode export without --with-revisions that'd also verity that the fix is working as intended and reflecting --mode flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added this test

Expand All @@ -73,12 +67,16 @@ func TestServiceExport(t *testing.T) {
{latestSvc: libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration()), servingtest.WithServiceLabel("a", "mouse"), servingtest.WithServiceAnnotation("a", "mouse"))},
{latestSvc: libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration()), servingtest.WithVolume("secretName", "/mountpath", volumeSource("secretName")))},
} {
exportServiceTest(t, &tc)
exportServiceTestForReplay(t, &tc)
tc.expectedKNExport = libtest.BuildKNExportWithOptions()
exportServiceTest(t, &tc, true)
//test default
exportServiceTest(t, &tc, false)
}
}

func exportServiceTest(t *testing.T, tc *testCase) {
output, err := executeServiceExportCommand(t, tc, "export", tc.latestSvc.ObjectMeta.Name, "-o", "yaml")
func exportServiceTestForReplay(t *testing.T, tc *testCase) {
output, err := executeServiceExportCommand(t, tc, "export", tc.latestSvc.ObjectMeta.Name, "--mode", "replay", "-o", "yaml")
assert.NilError(t, err)

actSvc := servingv1.Service{}
Expand All @@ -88,6 +86,23 @@ func exportServiceTest(t *testing.T, tc *testCase) {
assert.DeepEqual(t, tc.latestSvc, &actSvc)
}

func exportServiceTest(t *testing.T, tc *testCase, addMode bool) {
args := []string{"export", tc.latestSvc.ObjectMeta.Name, "-o", "json"}
if addMode {
args = append(args, []string{"--mode", "export"}...)
}
output, err := executeServiceExportCommand(t, tc, args...)
assert.NilError(t, err)

tc.expectedKNExport.Spec.Service = *tc.latestSvc

actKNExport := &clientv1alpha1.Export{}
err = json.Unmarshal([]byte(output), actKNExport)
assert.NilError(t, err)

assert.DeepEqual(t, tc.expectedKNExport, actKNExport)
}

func TestServiceExportwithMultipleRevisions(t *testing.T) {
for _, tc := range []testCase{{
name: "test 2 revisions with traffic split",
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/service_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ func TestServiceExport(t *testing.T) {
servingtest.WithConfigSpec(test.BuildConfigurationSpec()),
servingtest.WithBYORevisionName("hello-rev1"),
test.WithRevisionAnnotations(map[string]string{"client.knative.dev/user-image": pkgtest.ImagePath("helloworld")}),
), "-o", "json")
), "--mode", "replay", "-o", "json")

t.Log("update service - add env variable")
test.ServiceUpdate(r, "hello", "--env", "a=mouse", "--revision-name", "rev2", "--no-lock-to-digest")
serviceExport(r, "hello", test.BuildServiceWithOptions("hello",
servingtest.WithConfigSpec(test.BuildConfigurationSpec()),
servingtest.WithBYORevisionName("hello-rev2"),
servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}),
), "-o", "json")
), "--mode", "replay", "-o", "json")

t.Log("export service-revision2 with kubernetes-resources")
serviceExportWithServiceList(r, "hello", test.BuildServiceListWithOptions(
Expand Down