Skip to content

Commit

Permalink
add container source create and delete
Browse files Browse the repository at this point in the history
  • Loading branch information
Daisy Guo committed Nov 3, 2020
1 parent c60b851 commit 9676b19
Show file tree
Hide file tree
Showing 11 changed files with 896 additions and 0 deletions.
65 changes: 65 additions & 0 deletions pkg/kn/commands/source/container/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
Copyright 2020 The Knative Authors
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 container

import (
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/sources/v1alpha2"
clientv1alpha2 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2"
)

// NewContainerSourceCommand for managing ApiServer source
func NewContainerSourceCommand(p *commands.KnParams) *cobra.Command {
containerSourceCmd := &cobra.Command{
Use: "container COMMAND",
Short: "Manage container sources",
}
containerSourceCmd.AddCommand(NewContainerCreateCommand(p))
containerSourceCmd.AddCommand(NewContainerDeleteCommand(p))
return containerSourceCmd
}

var containerSourceClientFactory func(config clientcmd.ClientConfig, namespace string) (v1alpha2.KnContainerSourcesClient, error)

func newContainerSourceClient(p *commands.KnParams, cmd *cobra.Command) (v1alpha2.KnContainerSourcesClient, error) {
namespace, err := p.GetNamespace(cmd)
if err != nil {
return nil, err
}

if containerSourceClientFactory != nil {
config, err := p.GetClientConfig()
if err != nil {
return nil, err
}
return containerSourceClientFactory(config, namespace)
}

clientConfig, err := p.RestConfig()
if err != nil {
return nil, err
}

client, err := clientv1alpha2.NewForConfig(clientConfig)
if err != nil {
return nil, err
}

return v1alpha2.NewKnSourcesClient(client, namespace).ContainerSourcesClient(), nil
}
109 changes: 109 additions & 0 deletions pkg/kn/commands/source/container/container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
Copyright 2020 The Knative Authors
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 container

import (
"bytes"

corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/clientcmd"
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
duckv1 "knative.dev/pkg/apis/duck/v1"

kndynamic "knative.dev/client/pkg/dynamic"
clientv1alpha2 "knative.dev/client/pkg/sources/v1alpha2"

"knative.dev/client/pkg/kn/commands"
)

var blankConfig clientcmd.ClientConfig

// TODO: Remove that blankConfig hack for tests in favor of overwriting GetConfig()
func init() {
var err error
blankConfig, err = clientcmd.NewClientConfigFromBytes([]byte(`kind: Config
version: v1
users:
- name: u
clusters:
- name: c
cluster:
server: example.com
contexts:
- name: x
context:
user: u
cluster: c
current-context: x
`))
if err != nil {
panic(err)
}
}

func executeContainerSourceCommand(containerSourceClient clientv1alpha2.KnContainerSourcesClient, dynamicClient kndynamic.KnDynamicClient, args ...string) (string, error) {
knParams := &commands.KnParams{}
knParams.ClientConfig = blankConfig

output := new(bytes.Buffer)
knParams.Output = output
knParams.NewDynamicClient = func(namespace string) (kndynamic.KnDynamicClient, error) {
return dynamicClient, nil
}

cmd := NewContainerSourceCommand(knParams)
cmd.SetArgs(args)
cmd.SetOutput(output)

containerSourceClientFactory = func(config clientcmd.ClientConfig, namespace string) (clientv1alpha2.KnContainerSourcesClient, error) {
return containerSourceClient, nil
}
defer cleanupContainerServerMockClient()

err := cmd.Execute()

return output.String(), err
}

func cleanupContainerServerMockClient() {
containerSourceClientFactory = nil
}

func createContainerSource(name, image string, sink duckv1.Destination) *v1alpha2.ContainerSource {
return clientv1alpha2.NewContainerSourceBuilder(name).
PodSpec(corev1.PodSpec{
Containers: []corev1.Container{{
Image: image,
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{},
Requests: corev1.ResourceList{},
},
}}}).
Sink(sink).
Build()
}

func createSinkv1(serviceName, namespace string) duckv1.Destination {
return duckv1.Destination{
Ref: &duckv1.KReference{
Kind: "Service",
Name: serviceName,
APIVersion: "serving.knative.dev/v1",
Namespace: namespace,
},
}
}
99 changes: 99 additions & 0 deletions pkg/kn/commands/source/container/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
Copyright 2020 The Knative Authors
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 container

import (
"errors"
"fmt"

"github.com/spf13/cobra"
"knative.dev/client/pkg/kn/commands/flags"
knflags "knative.dev/client/pkg/kn/flags"

corev1 "k8s.io/api/core/v1"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/sources/v1alpha2"
)

// NewContainerCreateCommand for creating source
func NewContainerCreateCommand(p *commands.KnParams) *cobra.Command {
var podFlags knflags.PodSpecFlags
var sinkFlags flags.SinkFlags

cmd := &cobra.Command{
Use: "create NAME --image IMAGE",
Short: "Create a container source",
Example: `
# Create a ContainerSource 'containersrc' to instantiate an image 'docker.io/sample/image' that can generate events
kn source container create containersrc --image docker.io/sample/image`,

RunE: func(cmd *cobra.Command, args []string) (err error) {
if len(args) != 1 {
return errors.New("requires the name of the source to create as single argument")
}
name := args[0]

// get client
srcClient, err := newContainerSourceClient(p, cmd)
if err != nil {
return err
}

namespace := srcClient.Namespace()

dynamicClient, err := p.NewDynamicClient(namespace)
if err != nil {
return err
}

objectRef, err := sinkFlags.ResolveSink(dynamicClient, namespace)
if err != nil {
return fmt.Errorf(
"cannot create ContainerSource '%s' in namespace '%s' "+
"because: %s", name, namespace, err)
}

podSpec := &corev1.PodSpec{Containers: []corev1.Container{{}}}
err = podFlags.ResolvePodSpec(podSpec, cmd.Flags())
if err != nil {
return fmt.Errorf(
"cannot create ContainerSource '%s' in namespace '%s' "+
"because: %s", name, namespace, err)
}

b := v1alpha2.NewContainerSourceBuilder(name).Sink(*objectRef).PodSpec(*podSpec)
err = srcClient.CreateContainerSource(b.Build())
if err != nil {
return fmt.Errorf(
"cannot create ContainerSource '%s' in namespace '%s' "+
"because: %s", name, namespace, err)
}

if err == nil {
fmt.Fprintf(cmd.OutOrStdout(), "ContainerSource '%s' created in namespace '%s'.\n", args[0], namespace)
}

return err
},
}
commands.AddNamespaceFlags(cmd.Flags(), false)
podFlags.AddFlags(cmd.Flags())
sinkFlags.Add(cmd)
cmd.MarkFlagRequired("image")
cmd.MarkFlagRequired("sink")
return cmd
}
62 changes: 62 additions & 0 deletions pkg/kn/commands/source/container/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright 2020 The Knative Authors
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 container

import (
"testing"

"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"

dynamicfake "knative.dev/client/pkg/dynamic/fake"
"knative.dev/client/pkg/sources/v1alpha2"
"knative.dev/client/pkg/util"
)

func TestCreateContainerSource(t *testing.T) {
testsvc := &servingv1.Service{
TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1"},
ObjectMeta: metav1.ObjectMeta{Name: "testsvc", Namespace: "default"},
}
dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default", testsvc)
containerClient := v1alpha2.NewMockKnContainerSourceClient(t)

containerRecorder := containerClient.Recorder()
containerRecorder.CreateContainerSource(createContainerSource("testsource", "docker.io/test/testimg", createSinkv1("testsvc", "default")), nil)

out, err := executeContainerSourceCommand(containerClient, dynamicClient, "create", "testsource", "--image", "docker.io/test/testimg", "--sink", "ksvc:testsvc")
assert.NilError(t, err, "Container source should be created")
assert.Assert(t, util.ContainsAll(out, "created", "default", "testsource"))

containerRecorder.Validate()
}

func TestSinkNotFoundError(t *testing.T) {
dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
containerClient := v1alpha2.NewMockKnContainerSourceClient(t)
errorMsg := "cannot create ContainerSource 'testsource' in namespace 'default' because: services.serving.knative.dev \"testsvc\" not found"
out, err := executeContainerSourceCommand(containerClient, dynamicClient, "create", "testsource", "--image", "docker.io/test/testimg", "--sink", "ksvc:testsvc")
assert.Error(t, err, errorMsg)
assert.Assert(t, util.ContainsAll(out, errorMsg, "Usage"))
}

func TestNoSinkError(t *testing.T) {
containerClient := v1alpha2.NewMockKnContainerSourceClient(t)
_, err := executeContainerSourceCommand(containerClient, nil, "create", "testsource", "--image", "docker.io/test/testimg")
assert.ErrorContains(t, err, "required flag(s)", "sink", "not set")
}
Loading

0 comments on commit 9676b19

Please sign in to comment.