mirror of https://github.com/knative/client.git
Add command group for ContainerSource (#1016)
* add container source create and delete * add update and list commands * add describe command * add e2e test * add more tests * changes to address review comments
This commit is contained in:
parent
fb594e76c5
commit
45162fb5d8
|
|
@ -29,6 +29,7 @@ kn source SOURCE|COMMAND
|
|||
* [kn](kn.md) - kn manages Knative Serving and Eventing resources
|
||||
* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources
|
||||
* [kn source binding](kn_source_binding.md) - Manage sink bindings
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
* [kn source list](kn_source_list.md) - List event sources
|
||||
* [kn source list-types](kn_source_list-types.md) - List event source types
|
||||
* [kn source ping](kn_source_ping.md) - Manage ping sources
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
## kn source container
|
||||
|
||||
Manage container sources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Manage container sources
|
||||
|
||||
```
|
||||
kn source container create|delete|update|list|describe
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for container
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source](kn_source.md) - Manage event sources
|
||||
* [kn source container create](kn_source_container_create.md) - Create a container source
|
||||
* [kn source container delete](kn_source_container_delete.md) - Delete a container source
|
||||
* [kn source container describe](kn_source_container_describe.md) - Show details of a container source
|
||||
* [kn source container list](kn_source_container_list.md) - List container sources
|
||||
* [kn source container update](kn_source_container_update.md) - Update a container source
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
## kn source container create
|
||||
|
||||
Create a container source
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create a container source
|
||||
|
||||
```
|
||||
kn source container create NAME --image IMAGE --sink SINK
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
# Create a ContainerSource 'src' to start a container with image 'docker.io/sample/image' and send messages to service 'mysvc'
|
||||
kn source container create src --image docker.io/sample/image --sink ksvc:mysvc
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--arg stringArray Add argument to the container command. Example: --arg myArg1 --arg --myArg2 --arg myArg3=3. You can use this flag multiple times.
|
||||
--cmd string Specify command to be used as entrypoint instead of default one. Example: --cmd /app/start or --cmd /app/start --arg myArg to pass additional arguments.
|
||||
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).
|
||||
--env-from stringArray Add environment variables from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret:). Example: --env-from cm:myconfigmap or --env-from secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --env-from cm:myconfigmap-.
|
||||
-h, --help help for create
|
||||
--image string Image to run.
|
||||
--limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'.
|
||||
--mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume.
|
||||
-n, --namespace string Specify the namespace to operate in.
|
||||
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
||||
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
||||
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
||||
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
|
||||
-s, --sink string Addressable sink for events. You can specify a broker, channel, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink channel:pipe' for a channel 'pipe', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
|
||||
--user int The user ID to run the container (e.g., 1001).
|
||||
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
## kn source container delete
|
||||
|
||||
Delete a container source
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete a container source
|
||||
|
||||
```
|
||||
kn source container delete NAME
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
# Delete a ContainerSource 'containersrc' in default namespace
|
||||
kn source container delete containersrc
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for delete
|
||||
-n, --namespace string Specify the namespace to operate in.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
## kn source container describe
|
||||
|
||||
Show details of a container source
|
||||
|
||||
### Synopsis
|
||||
|
||||
Show details of a container source
|
||||
|
||||
```
|
||||
kn source container describe NAME
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
# Describe a container source with name 'k8sevents'
|
||||
kn source container describe k8sevents
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for describe
|
||||
-n, --namespace string Specify the namespace to operate in.
|
||||
-v, --verbose More output.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
## kn source container list
|
||||
|
||||
List container sources
|
||||
|
||||
### Synopsis
|
||||
|
||||
List container sources
|
||||
|
||||
```
|
||||
kn source container list
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
# List all Container sources
|
||||
kn source container list
|
||||
|
||||
# List all Container sources in YAML format
|
||||
kn source apiserver list -o yaml
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-A, --all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.
|
||||
--allow-missing-template-keys If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
|
||||
-h, --help help for list
|
||||
-n, --namespace string Specify the namespace to operate in.
|
||||
--no-headers When using the default output format, don't print headers (default: print headers).
|
||||
-o, --output string Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
|
||||
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
## kn source container update
|
||||
|
||||
Update a container source
|
||||
|
||||
### Synopsis
|
||||
|
||||
Update a container source
|
||||
|
||||
```
|
||||
kn source container update NAME --image IMAGE
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
# Update a ContainerSource 'src' with a different image uri 'docker.io/sample/newimage'
|
||||
kn source container update src --image docker.io/sample/newimage
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--arg stringArray Add argument to the container command. Example: --arg myArg1 --arg --myArg2 --arg myArg3=3. You can use this flag multiple times.
|
||||
--cmd string Specify command to be used as entrypoint instead of default one. Example: --cmd /app/start or --cmd /app/start --arg myArg to pass additional arguments.
|
||||
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).
|
||||
--env-from stringArray Add environment variables from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret:). Example: --env-from cm:myconfigmap or --env-from secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --env-from cm:myconfigmap-.
|
||||
-h, --help help for update
|
||||
--image string Image to run.
|
||||
--limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'.
|
||||
--mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume.
|
||||
-n, --namespace string Specify the namespace to operate in.
|
||||
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
||||
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
||||
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
||||
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
|
||||
-s, --sink string Addressable sink for events. You can specify a broker, channel, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink channel:pipe' for a channel 'pipe', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
|
||||
--user int The user ID to run the container (e.g., 1001).
|
||||
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string kn configuration file (default: ~/.config/kn/config.yaml)
|
||||
--kubeconfig string kubectl configuration file (default: ~/.kube/config)
|
||||
--log-http log http traffic
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kn source container](kn_source_container.md) - Manage container sources
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
// NewContainerCommand for managing Container source
|
||||
func NewContainerCommand(p *commands.KnParams) *cobra.Command {
|
||||
containerSourceCmd := &cobra.Command{
|
||||
Use: "container create|delete|update|list|describe",
|
||||
Short: "Manage container sources",
|
||||
}
|
||||
containerSourceCmd.AddCommand(NewContainerCreateCommand(p))
|
||||
containerSourceCmd.AddCommand(NewContainerDeleteCommand(p))
|
||||
containerSourceCmd.AddCommand(NewContainerUpdateCommand(p))
|
||||
containerSourceCmd.AddCommand(NewContainerListCommand(p))
|
||||
containerSourceCmd.AddCommand(NewContainerDescribeCommand(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
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
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
|
||||
|
||||
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 := NewContainerCommand(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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
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 --sink SINK",
|
||||
Short: "Create a container source",
|
||||
Example: `
|
||||
# Create a ContainerSource 'src' to start a container with image 'docker.io/sample/image' and send messages to service 'mysvc'
|
||||
kn source container create src --image docker.io/sample/image --sink ksvc:mysvc`,
|
||||
|
||||
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]
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "ContainerSource '%s' created in namespace '%s'.\n", args[0], namespace)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
commands.AddNamespaceFlags(cmd.Flags(), false)
|
||||
podFlags.AddFlags(cmd.Flags())
|
||||
sinkFlags.Add(cmd)
|
||||
cmd.MarkFlagRequired("image")
|
||||
cmd.MarkFlagRequired("sink")
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
// NewContainerDeleteCommand for deleting source
|
||||
func NewContainerDeleteCommand(p *commands.KnParams) *cobra.Command {
|
||||
deleteCommand := &cobra.Command{
|
||||
Use: "delete NAME",
|
||||
Short: "Delete a container source",
|
||||
Example: `
|
||||
# Delete a ContainerSource 'containersrc' in default namespace
|
||||
kn source container delete containersrc`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("requires the name of the source as single argument")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
namespace, err := p.GetNamespace(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get client
|
||||
srcClient, err := newContainerSourceClient(p, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = srcClient.DeleteContainerSource(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "ContainerSourcd '%s' deleted in namespace '%s'.\n", args[0], namespace)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
commands.AddNamespaceFlags(deleteCommand.Flags(), false)
|
||||
return deleteCommand
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
"knative.dev/client/pkg/sources/v1alpha2"
|
||||
"knative.dev/client/pkg/util"
|
||||
)
|
||||
|
||||
func TestContainerSourceDelete(t *testing.T) {
|
||||
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t, "testns")
|
||||
containerRecorder := containerClient.Recorder()
|
||||
|
||||
containerRecorder.DeleteContainerSource("testsource", nil)
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "delete", "testsource")
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(out, "deleted", "default", "testsource"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
||||
func TestDeleteWithError(t *testing.T) {
|
||||
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t, "mynamespace")
|
||||
containerRecorder := containerClient.Recorder()
|
||||
|
||||
containerRecorder.DeleteContainerSource("testsource", errors.New("container source testsource not found"))
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "delete", "testsource")
|
||||
assert.ErrorContains(t, err, "testsource")
|
||||
assert.Assert(t, util.ContainsAll(out, "container", "source", "testsource", "not found"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
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"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"knative.dev/client/lib/printing"
|
||||
"knative.dev/client/pkg/kn/commands"
|
||||
"knative.dev/client/pkg/printers"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
)
|
||||
|
||||
// NewContainerDescribeCommand to describe an Container source object
|
||||
func NewContainerDescribeCommand(p *commands.KnParams) *cobra.Command {
|
||||
apiServerDescribe := &cobra.Command{
|
||||
Use: "describe NAME",
|
||||
Short: "Show details of a container source",
|
||||
Example: `
|
||||
# Describe a container source with name 'k8sevents'
|
||||
kn source container describe k8sevents`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("'kn source container describe' requires name of the source as single argument")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
sourceClient, err := newContainerSourceClient(p, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := sourceClient.GetContainerSource(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
dw := printers.NewPrefixWriter(out)
|
||||
|
||||
printDetails, err := cmd.Flags().GetBool("verbose")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContainerSource(dw, source, printDetails)
|
||||
dw.WriteLine()
|
||||
if err := dw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printing.DescribeSink(dw, "Sink", source.Namespace, &source.Spec.Sink)
|
||||
dw.WriteLine()
|
||||
if err := dw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if source.Spec.CloudEventOverrides != nil && source.Spec.CloudEventOverrides.Extensions != nil {
|
||||
writeCeOverrides(dw, source.Spec.CloudEventOverrides.Extensions)
|
||||
}
|
||||
|
||||
dw.WriteLine()
|
||||
if err := dw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Condition info
|
||||
commands.WriteConditions(dw, source.Status.Conditions, printDetails)
|
||||
if err := dw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
flags := apiServerDescribe.Flags()
|
||||
commands.AddNamespaceFlags(flags, false)
|
||||
flags.BoolP("verbose", "v", false, "More output.")
|
||||
|
||||
return apiServerDescribe
|
||||
}
|
||||
|
||||
func writeContainerSource(dw printers.PrefixWriter, source *v1alpha2.ContainerSource, printDetails bool) {
|
||||
commands.WriteMetadata(dw, &source.ObjectMeta, printDetails)
|
||||
writeContainer(dw, &source.Spec.Template.Spec.Containers[0])
|
||||
}
|
||||
|
||||
func writeCeOverrides(dw printers.PrefixWriter, ceOverrides map[string]string) {
|
||||
subDw := dw.WriteAttribute("CloudEvent Overrides", "")
|
||||
keys := make([]string, 0, len(ceOverrides))
|
||||
for k := range ceOverrides {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
subDw.WriteAttribute(k, ceOverrides[k])
|
||||
}
|
||||
}
|
||||
|
||||
func writeContainer(dw printers.PrefixWriter, container *corev1.Container) {
|
||||
subDw := dw.WriteAttribute("Container", "")
|
||||
subDw.WriteAttribute("Image", container.Image)
|
||||
if len(container.Env) > 0 {
|
||||
envDw := subDw.WriteAttribute("Env", "")
|
||||
for _, env := range container.Env {
|
||||
value := env.Value
|
||||
if env.ValueFrom != nil {
|
||||
value = "[ref]"
|
||||
}
|
||||
envDw.WriteAttribute(env.Name, value)
|
||||
}
|
||||
}
|
||||
if len(container.Args) > 0 {
|
||||
envDw := subDw.WriteAttribute("Args", "")
|
||||
for _, k := range container.Args {
|
||||
envDw.WriteAttribute(k, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"knative.dev/client/pkg/sources/v1alpha2"
|
||||
"knative.dev/client/pkg/util"
|
||||
)
|
||||
|
||||
func TestDescribeError(t *testing.T) {
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t, "mynamespace")
|
||||
|
||||
containerRecorder := containerClient.Recorder()
|
||||
containerRecorder.GetContainerSource("testsource", nil, errors.New("no container source testsource"))
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "describe", "testsource")
|
||||
assert.ErrorContains(t, err, "testsource")
|
||||
assert.Assert(t, util.ContainsAll(out, "Usage", "testsource"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
||||
func TestSimpleDescribe(t *testing.T) {
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t, "mynamespace")
|
||||
|
||||
containerRecorder := containerClient.Recorder()
|
||||
sampleSource := createContainerSource("testsource", "docker.io/test/testimg", createSinkv1("testsvc", "default"))
|
||||
sampleSource.Namespace = "mynamespace"
|
||||
containerRecorder.GetContainerSource("testsource", sampleSource, nil)
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "describe", "testsource")
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(out, "testsource", "docker.io/test/testimg", "testsvc"))
|
||||
assert.Assert(t, util.ContainsNone(out, "URI"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
|
||||
"knative.dev/client/pkg/kn/commands"
|
||||
"knative.dev/client/pkg/kn/commands/flags"
|
||||
|
||||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||
|
||||
hprinters "knative.dev/client/pkg/printers"
|
||||
)
|
||||
|
||||
// ContainerSourceListHandlers handles printing human readable table for `kn source apiserver list` command's output
|
||||
func ContainerSourceListHandlers(h hprinters.PrintHandler) {
|
||||
sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
|
||||
{Name: "Namespace", Type: "string", Description: "Namespace of the Container source", Priority: 0},
|
||||
{Name: "Name", Type: "string", Description: "Name of the Container source", Priority: 1},
|
||||
{Name: "Image", Type: "string", Description: "Image URI configured for the Container source", Priority: 1},
|
||||
{Name: "Sink", Type: "string", Description: "Sink of the Container source", Priority: 1},
|
||||
{Name: "Age", Type: "string", Description: "Age of the Container source", Priority: 1},
|
||||
{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
|
||||
{Name: "Ready", Type: "string", Description: "Ready state of the Container source", Priority: 1},
|
||||
{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
|
||||
}
|
||||
h.TableHandler(sourceColumnDefinitions, printSource)
|
||||
h.TableHandler(sourceColumnDefinitions, printSourceList)
|
||||
}
|
||||
|
||||
// printSource populates a single row of source apiserver list table
|
||||
func printSource(source *v1alpha2.ContainerSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||
row := metav1beta1.TableRow{
|
||||
Object: runtime.RawExtension{Object: source},
|
||||
}
|
||||
|
||||
name := source.Name
|
||||
age := commands.TranslateTimestampSince(source.CreationTimestamp)
|
||||
conditions := commands.ConditionsValue(source.Status.Conditions)
|
||||
ready := commands.ReadyCondition(source.Status.Conditions)
|
||||
reason := strings.TrimSpace(commands.NonReadyConditionReason(source.Status.Conditions))
|
||||
image := source.Spec.Template.Spec.Containers[0].Image
|
||||
|
||||
// Not moving to SinkToString() as it references v1beta1.Destination
|
||||
// This source is going to be moved/removed soon to v1, so no need to move
|
||||
// it now
|
||||
sink := flags.SinkToString(source.Spec.Sink)
|
||||
|
||||
if options.AllNamespaces {
|
||||
row.Cells = append(row.Cells, source.Namespace)
|
||||
}
|
||||
|
||||
row.Cells = append(row.Cells, name, image, sink, age, conditions, ready, reason)
|
||||
return []metav1beta1.TableRow{row}, nil
|
||||
}
|
||||
|
||||
// printSourceList populates the source apiserver list table rows
|
||||
func printSourceList(sourceList *v1alpha2.ContainerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||
if options.AllNamespaces {
|
||||
return printSourceListWithNamespace(sourceList, options)
|
||||
}
|
||||
|
||||
rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
|
||||
|
||||
sort.SliceStable(sourceList.Items, func(i, j int) bool {
|
||||
return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
|
||||
})
|
||||
|
||||
for _, item := range sourceList.Items {
|
||||
row, err := printSource(&item, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows = append(rows, row...)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
// printSourceListWithNamespace populates the knative service table rows with namespace column
|
||||
func printSourceListWithNamespace(sourceList *v1alpha2.ContainerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||
rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
|
||||
|
||||
// temporary slice for sorting services in non-default namespace
|
||||
others := []metav1beta1.TableRow{}
|
||||
|
||||
for _, source := range sourceList.Items {
|
||||
// Fill in with services in `default` namespace at first
|
||||
if source.Namespace == "default" {
|
||||
r, err := printSource(&source, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows = append(rows, r...)
|
||||
continue
|
||||
}
|
||||
// put other services in temporary slice
|
||||
r, err := printSource(&source, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
others = append(others, r...)
|
||||
}
|
||||
|
||||
// sort other services list alphabetically by namespace
|
||||
sort.SliceStable(others, func(i, j int) bool {
|
||||
return others[i].Cells[0].(string) < others[j].Cells[0].(string)
|
||||
})
|
||||
|
||||
return append(rows, others...), nil
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"knative.dev/client/pkg/kn/commands"
|
||||
"knative.dev/client/pkg/kn/commands/flags"
|
||||
)
|
||||
|
||||
// NewContainerListCommand is for listing Container sources
|
||||
func NewContainerListCommand(p *commands.KnParams) *cobra.Command {
|
||||
listFlags := flags.NewListPrintFlags(ContainerSourceListHandlers)
|
||||
|
||||
listCommand := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List container sources",
|
||||
Example: `
|
||||
# List all Container sources
|
||||
kn source container list
|
||||
|
||||
# List all Container sources in YAML format
|
||||
kn source apiserver list -o yaml`,
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
containerClient, err := newContainerSourceClient(p, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sourceList, err := containerClient.ListContainerSources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(sourceList.Items) == 0 {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "No Container source found.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
if containerClient.Namespace() == "" {
|
||||
listFlags.EnsureWithNamespace()
|
||||
}
|
||||
|
||||
return listFlags.Print(sourceList, cmd.OutOrStdout())
|
||||
},
|
||||
}
|
||||
commands.AddNamespaceFlags(listCommand.Flags(), true)
|
||||
listFlags.AddFlags(listCommand)
|
||||
return listCommand
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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"
|
||||
v1alpha22 "knative.dev/client/pkg/sources/v1alpha2"
|
||||
"knative.dev/client/pkg/util"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
)
|
||||
|
||||
func TestListContainerSource(t *testing.T) {
|
||||
containerClient := v1alpha22.NewMockKnContainerSourceClient(t)
|
||||
|
||||
containerRecorder := containerClient.Recorder()
|
||||
sampleSource := createContainerSource("testsource", "docker.io/test/newimg", createSinkv1("svc2", "default"))
|
||||
sampleSourceList := v1alpha2.ContainerSourceList{}
|
||||
sampleSourceList.Items = []v1alpha2.ContainerSource{*sampleSource}
|
||||
|
||||
containerRecorder.ListContainerSources(&sampleSourceList, nil)
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "list")
|
||||
assert.NilError(t, err, "sources should be listed")
|
||||
assert.Assert(t, util.ContainsAll(out, "NAME", "IMAGE", "SINK", "AGE", "CONDITIONS", "READY", "REASON"))
|
||||
assert.Assert(t, util.ContainsAll(out, "testsource", "docker.io/test/newimg", "ksvc:svc2"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
||||
func TestListContainerSourceEmpty(t *testing.T) {
|
||||
containerClient := v1alpha22.NewMockKnContainerSourceClient(t)
|
||||
|
||||
containerRecorder := containerClient.Recorder()
|
||||
sampleSourceList := v1alpha2.ContainerSourceList{}
|
||||
|
||||
containerRecorder.ListContainerSources(&sampleSourceList, nil)
|
||||
|
||||
out, err := executeContainerSourceCommand(containerClient, nil, "list")
|
||||
assert.NilError(t, err, "Sources should be listed")
|
||||
assert.Assert(t, util.ContainsNone(out, "NAME", "IMAGE", "SINK", "AGE", "CONDITIONS", "READY", "REASON"))
|
||||
assert.Assert(t, util.ContainsAll(out, "No", "Container", "source", "found"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
"knative.dev/client/pkg/kn/commands"
|
||||
"knative.dev/client/pkg/sources/v1alpha2"
|
||||
)
|
||||
|
||||
// NewContainerUpdateCommand for managing source update
|
||||
func NewContainerUpdateCommand(p *commands.KnParams) *cobra.Command {
|
||||
var podFlags knflags.PodSpecFlags
|
||||
var sinkFlags flags.SinkFlags
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "update NAME --image IMAGE",
|
||||
Short: "Update a container source",
|
||||
Example: `
|
||||
# Update a ContainerSource 'src' with a different image uri 'docker.io/sample/newimage'
|
||||
kn source container update src --image docker.io/sample/newimage`,
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
if len(args) != 1 {
|
||||
return errors.New("requires the name of the source 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
|
||||
}
|
||||
|
||||
source, err := srcClient.GetContainerSource(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if source.GetDeletionTimestamp() != nil {
|
||||
return fmt.Errorf("can't update container source %s because it has been marked for deletion", name)
|
||||
}
|
||||
|
||||
b := v1alpha2.NewContainerSourceBuilderFromExisting(source)
|
||||
podSpec := b.Build().Spec.Template.Spec
|
||||
err = podFlags.ResolvePodSpec(&podSpec, cmd.Flags())
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"cannot update ContainerSource '%s' in namespace '%s' "+
|
||||
"because: %s", name, namespace, err)
|
||||
}
|
||||
b.PodSpec(podSpec)
|
||||
|
||||
if cmd.Flags().Changed("sink") {
|
||||
objectRef, err := sinkFlags.ResolveSink(dynamicClient, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"cannot update ContainerSource '%s' in namespace '%s' "+
|
||||
"because: %s", name, namespace, err)
|
||||
}
|
||||
b.Sink(*objectRef)
|
||||
}
|
||||
|
||||
err = srcClient.UpdateContainerSource(b.Build())
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"cannot update ContainerSource '%s' in namespace '%s' "+
|
||||
"because: %s", name, namespace, err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Container source '%s' updated in namespace '%s'.\n", args[0], namespace)
|
||||
return err
|
||||
},
|
||||
}
|
||||
commands.AddNamespaceFlags(cmd.Flags(), false)
|
||||
podFlags.AddFlags(cmd.Flags())
|
||||
sinkFlags.Add(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -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"
|
||||
dynamicfake "knative.dev/client/pkg/dynamic/fake"
|
||||
"knative.dev/client/pkg/sources/v1alpha2"
|
||||
"knative.dev/client/pkg/util"
|
||||
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
|
||||
)
|
||||
|
||||
func TestContainerSourceUpdate(t *testing.T) {
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t)
|
||||
dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default", &servingv1.Service{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1"},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "svc2", Namespace: "default"},
|
||||
})
|
||||
|
||||
containerRecorder := containerClient.Recorder()
|
||||
|
||||
present := createContainerSource("testsource", "docker.io/test/testimg", createSinkv1("svc2", "default"))
|
||||
containerRecorder.GetContainerSource("testsource", present, nil)
|
||||
|
||||
updated := createContainerSource("testsource", "docker.io/test/newimg", createSinkv1("svc2", "default"))
|
||||
containerRecorder.UpdateContainerSource(updated, nil)
|
||||
|
||||
output, err := executeContainerSourceCommand(containerClient, dynamicClient, "update", "testsource", "--image", "docker.io/test/newimg")
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(output, "testsource", "updated", "default"))
|
||||
|
||||
containerRecorder.Validate()
|
||||
}
|
||||
|
||||
func TestContainerSourceUpdateSinkError(t *testing.T) {
|
||||
containerClient := v1alpha2.NewMockKnContainerSourceClient(t)
|
||||
dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
|
||||
containerRecorder := containerClient.Recorder()
|
||||
present := createContainerSource("testsource", "docker.io/test/testimg", createSinkv1("svc2", "default"))
|
||||
containerRecorder.GetContainerSource("testsource", present, nil)
|
||||
errorMsg := "cannot update ContainerSource 'testsource' in namespace 'default' because: services.serving.knative.dev \"testsvc\" not found"
|
||||
out, err := executeContainerSourceCommand(containerClient, dynamicClient, "update", "testsource", "--sink", "ksvc:testsvc")
|
||||
assert.Error(t, err, errorMsg)
|
||||
assert.Assert(t, util.ContainsAll(out, errorMsg, "Usage"))
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"knative.dev/client/pkg/kn/commands"
|
||||
"knative.dev/client/pkg/kn/commands/source/apiserver"
|
||||
"knative.dev/client/pkg/kn/commands/source/binding"
|
||||
"knative.dev/client/pkg/kn/commands/source/container"
|
||||
"knative.dev/client/pkg/kn/commands/source/ping"
|
||||
)
|
||||
|
||||
|
|
@ -34,5 +35,6 @@ func NewSourceCommand(p *commands.KnParams) *cobra.Command {
|
|||
sourceCmd.AddCommand(apiserver.NewAPIServerCommand(p))
|
||||
sourceCmd.AddCommand(ping.NewPingCommand(p))
|
||||
sourceCmd.AddCommand(binding.NewBindingCommand(p))
|
||||
sourceCmd.AddCommand(container.NewContainerCommand(p))
|
||||
return sourceCmd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,6 @@ func (p *PodSpecFlags) AddFlags(flagset *pflag.FlagSet) []string {
|
|||
// ResolvePodSpec will create corev1.PodSpec based on the flag inputs
|
||||
func (p *PodSpecFlags) ResolvePodSpec(podSpec *corev1.PodSpec, flags *pflag.FlagSet) error {
|
||||
var err error
|
||||
|
||||
if flags.Changed("env") {
|
||||
envMap, err := util.MapFromArrayAllowingSingles(p.Env, "=")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ type KnSourcesClient interface {
|
|||
|
||||
// Get client for ApiServer sources
|
||||
APIServerSourcesClient() KnAPIServerSourcesClient
|
||||
|
||||
// Get client for container sources
|
||||
ContainerSourcesClient() KnContainerSourcesClient
|
||||
}
|
||||
|
||||
// sourcesClient is a combination of Sources client interface and namespace
|
||||
|
|
@ -64,6 +67,11 @@ func (c *sourcesClient) APIServerSourcesClient() KnAPIServerSourcesClient {
|
|||
return newKnAPIServerSourcesClient(c.client.ApiServerSources(c.namespace), c.namespace)
|
||||
}
|
||||
|
||||
// ApiServerSourcesClient for dealing with ApiServer sources
|
||||
func (c *sourcesClient) ContainerSourcesClient() KnContainerSourcesClient {
|
||||
return newKnContainerSourcesClient(c.client.ContainerSources(c.namespace), c.namespace)
|
||||
}
|
||||
|
||||
// BuiltInSourcesGVKs returns the GVKs for built in sources
|
||||
func BuiltInSourcesGVKs() []schema.GroupVersionKind {
|
||||
return []schema.GroupVersionKind{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
knerrors "knative.dev/client/pkg/errors"
|
||||
"knative.dev/client/pkg/util"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
"knative.dev/eventing/pkg/client/clientset/versioned/scheme"
|
||||
clientv1alpha2 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2"
|
||||
duckv1 "knative.dev/pkg/apis/duck/v1"
|
||||
)
|
||||
|
||||
// KnContainerSourcesClient interface for working with ApiServer sources
|
||||
type KnContainerSourcesClient interface {
|
||||
|
||||
// Get an ContainerSource by name
|
||||
GetContainerSource(name string) (*v1alpha2.ContainerSource, error)
|
||||
|
||||
// Create an ContainerSource by object
|
||||
CreateContainerSource(containerSrc *v1alpha2.ContainerSource) error
|
||||
|
||||
// Update an ContainerSource by object
|
||||
UpdateContainerSource(containerSrc *v1alpha2.ContainerSource) error
|
||||
|
||||
// Delete an ContainerSource by name
|
||||
DeleteContainerSource(name string) error
|
||||
|
||||
// List ContainerSource
|
||||
ListContainerSources() (*v1alpha2.ContainerSourceList, error)
|
||||
|
||||
// Get namespace for this client
|
||||
Namespace() string
|
||||
}
|
||||
|
||||
// knSourcesClient is a combination of Sources client interface and namespace
|
||||
// Temporarily help to add sources dependencies
|
||||
// May be changed when adding real sources features
|
||||
type containerSourcesClient struct {
|
||||
client clientv1alpha2.ContainerSourceInterface
|
||||
namespace string
|
||||
}
|
||||
|
||||
// newKnContainerSourcesClient is to invoke Eventing Sources Client API to create object
|
||||
func newKnContainerSourcesClient(client clientv1alpha2.ContainerSourceInterface, namespace string) KnContainerSourcesClient {
|
||||
return &containerSourcesClient{
|
||||
client: client,
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
//GetContainerSource returns containerSrc object if present
|
||||
func (c *containerSourcesClient) GetContainerSource(name string) (*v1alpha2.ContainerSource, error) {
|
||||
containerSrc, err := c.client.Get(context.TODO(), name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, knerrors.GetError(err)
|
||||
}
|
||||
|
||||
return containerSrc, nil
|
||||
}
|
||||
|
||||
//CreateContainerSource is used to create an instance of ContainerSource
|
||||
func (c *containerSourcesClient) CreateContainerSource(containerSrc *v1alpha2.ContainerSource) error {
|
||||
_, err := c.client.Create(context.TODO(), containerSrc, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return knerrors.GetError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//UpdateContainerSource is used to update an instance of ContainerSource
|
||||
func (c *containerSourcesClient) UpdateContainerSource(containerSrc *v1alpha2.ContainerSource) error {
|
||||
_, err := c.client.Update(context.TODO(), containerSrc, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return knerrors.GetError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//DeleteContainerSource is used to create an instance of ContainerSource
|
||||
func (c *containerSourcesClient) DeleteContainerSource(name string) error {
|
||||
return c.client.Delete(context.TODO(), name, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
// Return the client's namespace
|
||||
func (c *containerSourcesClient) Namespace() string {
|
||||
return c.namespace
|
||||
}
|
||||
|
||||
// ListContainerSource returns the available container sources
|
||||
func (c *containerSourcesClient) ListContainerSources() (*v1alpha2.ContainerSourceList, error) {
|
||||
sourceList, err := c.client.List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, knerrors.GetError(err)
|
||||
}
|
||||
|
||||
containerListNew := sourceList.DeepCopy()
|
||||
err = updateContainerSourceGvk(containerListNew)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
containerListNew.Items = make([]v1alpha2.ContainerSource, len(sourceList.Items))
|
||||
for idx, binding := range sourceList.Items {
|
||||
bindingClone := binding.DeepCopy()
|
||||
err := updateSinkBindingGvk(bindingClone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerListNew.Items[idx] = *bindingClone
|
||||
}
|
||||
|
||||
return containerListNew, nil
|
||||
}
|
||||
|
||||
// update with the v1alpha2 group + version
|
||||
func updateContainerSourceGvk(obj runtime.Object) error {
|
||||
return util.UpdateGroupVersionKindWithScheme(obj, v1alpha2.SchemeGroupVersion, scheme.Scheme)
|
||||
}
|
||||
|
||||
// ContainerSourceBuilder is for building the source
|
||||
type ContainerSourceBuilder struct {
|
||||
ContainerSource *v1alpha2.ContainerSource
|
||||
}
|
||||
|
||||
// NewContainerSourceBuilder for building Container source object
|
||||
func NewContainerSourceBuilder(name string) *ContainerSourceBuilder {
|
||||
return &ContainerSourceBuilder{ContainerSource: &v1alpha2.ContainerSource{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// NewContainerSourceBuilderFromExisting for building the object from existing ContainerSource object
|
||||
func NewContainerSourceBuilderFromExisting(ContainerSource *v1alpha2.ContainerSource) *ContainerSourceBuilder {
|
||||
return &ContainerSourceBuilder{ContainerSource: ContainerSource.DeepCopy()}
|
||||
}
|
||||
|
||||
// Sink or destination of the source
|
||||
func (b *ContainerSourceBuilder) Sink(sink duckv1.Destination) *ContainerSourceBuilder {
|
||||
b.ContainerSource.Spec.Sink = sink
|
||||
return b
|
||||
}
|
||||
|
||||
// Build the ContainerSource object
|
||||
func (b *ContainerSourceBuilder) Build() *v1alpha2.ContainerSource {
|
||||
return b.ContainerSource
|
||||
}
|
||||
|
||||
// PodSpec defines the PodSpec
|
||||
func (b *ContainerSourceBuilder) PodSpec(podSpec corev1.PodSpec) *ContainerSourceBuilder {
|
||||
b.ContainerSource.Spec.Template.Spec = podSpec
|
||||
return b
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"knative.dev/client/pkg/util/mock"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
)
|
||||
|
||||
// MockKnContainerSourceClient is a combine of test object and recorder
|
||||
type MockKnContainerSourceClient struct {
|
||||
t *testing.T
|
||||
recorder *ConainterSourceRecorder
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewMockKnContainerSourceClient returns a new mock instance which you need to record for
|
||||
func NewMockKnContainerSourceClient(t *testing.T, ns ...string) *MockKnContainerSourceClient {
|
||||
namespace := "default"
|
||||
if len(ns) > 0 {
|
||||
namespace = ns[0]
|
||||
}
|
||||
return &MockKnContainerSourceClient{
|
||||
t: t,
|
||||
recorder: &ConainterSourceRecorder{mock.NewRecorder(t, namespace)},
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the interface is implemented
|
||||
var _ KnContainerSourcesClient = &MockKnContainerSourceClient{}
|
||||
|
||||
// ConainterSourceRecorder is recorder for eventing objects
|
||||
type ConainterSourceRecorder struct {
|
||||
r *mock.Recorder
|
||||
}
|
||||
|
||||
// Recorder returns the recorder for registering API calls
|
||||
func (c *MockKnContainerSourceClient) Recorder() *ConainterSourceRecorder {
|
||||
return c.recorder
|
||||
}
|
||||
|
||||
// Namespace of this client
|
||||
func (c *MockKnContainerSourceClient) Namespace() string {
|
||||
return c.recorder.r.Namespace()
|
||||
}
|
||||
|
||||
// CreateContainerSource records a call for CreateContainerSource with the expected error
|
||||
func (sr *ConainterSourceRecorder) CreateContainerSource(binding interface{}, err error) {
|
||||
sr.r.Add("CreateContainerSource", []interface{}{binding}, []interface{}{err})
|
||||
}
|
||||
|
||||
// CreateContainerSource performs a previously recorded action
|
||||
func (c *MockKnContainerSourceClient) CreateContainerSource(binding *v1alpha2.ContainerSource) error {
|
||||
call := c.recorder.r.VerifyCall("CreateContainerSource", binding)
|
||||
return mock.ErrorOrNil(call.Result[0])
|
||||
}
|
||||
|
||||
// GetContainerSource records a call for GetContainerSource with the expected object or error. Either binding or err should be nil
|
||||
func (sr *ConainterSourceRecorder) GetContainerSource(name interface{}, binding *v1alpha2.ContainerSource, err error) {
|
||||
sr.r.Add("GetContainerSource", []interface{}{name}, []interface{}{binding, err})
|
||||
}
|
||||
|
||||
// GetContainerSource performs a previously recorded action
|
||||
func (c *MockKnContainerSourceClient) GetContainerSource(name string) (*v1alpha2.ContainerSource, error) {
|
||||
call := c.recorder.r.VerifyCall("GetContainerSource", name)
|
||||
return call.Result[0].(*v1alpha2.ContainerSource), mock.ErrorOrNil(call.Result[1])
|
||||
}
|
||||
|
||||
// DeleteContainerSource records a call for DeleteContainerSource with the expected error (nil if none)
|
||||
func (sr *ConainterSourceRecorder) DeleteContainerSource(name interface{}, err error) {
|
||||
sr.r.Add("DeleteContainerSource", []interface{}{name}, []interface{}{err})
|
||||
}
|
||||
|
||||
// DeleteContainerSource performs a previously recorded action, failing if non has been registered
|
||||
func (c *MockKnContainerSourceClient) DeleteContainerSource(name string) error {
|
||||
call := c.recorder.r.VerifyCall("DeleteContainerSource", name)
|
||||
return mock.ErrorOrNil(call.Result[0])
|
||||
}
|
||||
|
||||
// ListContainerSources records a call for ListContainerSources with the expected result and error (nil if none)
|
||||
func (sr *ConainterSourceRecorder) ListContainerSources(bindingList *v1alpha2.ContainerSourceList, err error) {
|
||||
sr.r.Add("ListContainerSources", nil, []interface{}{bindingList, err})
|
||||
}
|
||||
|
||||
// ListContainerSources performs a previously recorded action
|
||||
func (c *MockKnContainerSourceClient) ListContainerSources() (*v1alpha2.ContainerSourceList, error) {
|
||||
call := c.recorder.r.VerifyCall("ListContainerSources")
|
||||
return call.Result[0].(*v1alpha2.ContainerSourceList), mock.ErrorOrNil(call.Result[1])
|
||||
}
|
||||
|
||||
// UpdateContainerSource records a call for ListContainerSources with the expected result and error (nil if none)
|
||||
func (sr *ConainterSourceRecorder) UpdateContainerSource(binding interface{}, err error) {
|
||||
sr.r.Add("UpdateContainerSource", []interface{}{binding}, []interface{}{err})
|
||||
}
|
||||
|
||||
// UpdateContainerSource performs a previously recorded action
|
||||
func (c *MockKnContainerSourceClient) UpdateContainerSource(binding *v1alpha2.ContainerSource) error {
|
||||
call := c.recorder.r.VerifyCall("UpdateContainerSource")
|
||||
return mock.ErrorOrNil(call.Result[0])
|
||||
}
|
||||
|
||||
// Validate validates whether every recorded action has been called
|
||||
func (sr *ConainterSourceRecorder) Validate() {
|
||||
sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
)
|
||||
|
||||
func TestMockKnConatinerSourceClient(t *testing.T) {
|
||||
client := NewMockKnContainerSourceClient(t)
|
||||
|
||||
recorder := client.Recorder()
|
||||
|
||||
// Record all services
|
||||
recorder.GetContainerSource("hello", nil, nil)
|
||||
recorder.CreateContainerSource(&v1alpha2.ContainerSource{}, nil)
|
||||
recorder.DeleteContainerSource("hello", nil)
|
||||
recorder.ListContainerSources(nil, nil)
|
||||
recorder.UpdateContainerSource(&v1alpha2.ContainerSource{}, nil)
|
||||
|
||||
// Call all service
|
||||
client.GetContainerSource("hello")
|
||||
client.CreateContainerSource(&v1alpha2.ContainerSource{})
|
||||
client.DeleteContainerSource("hello")
|
||||
client.ListContainerSources()
|
||||
client.UpdateContainerSource(&v1alpha2.ContainerSource{})
|
||||
|
||||
// Validate
|
||||
recorder.Validate()
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
|
||||
fake "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake"
|
||||
duckv1 "knative.dev/pkg/apis/duck/v1"
|
||||
)
|
||||
|
||||
func setupFakeContainerSourcesClient() (fakeSvr fake.FakeSourcesV1alpha2, client KnContainerSourcesClient) {
|
||||
fakeE := fake.FakeSourcesV1alpha2{Fake: &clienttesting.Fake{}}
|
||||
cli := NewKnSourcesClient(&fakeE, "test-ns").ContainerSourcesClient()
|
||||
return fakeE, cli
|
||||
}
|
||||
|
||||
func TestDeleteContainerSourceSource(t *testing.T) {
|
||||
sourcesServer, client := setupFakeContainerSourcesClient()
|
||||
|
||||
sourcesServer.AddReactor("delete", "containersources",
|
||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||
name := a.(clienttesting.DeleteAction).GetName()
|
||||
fmt.Printf("name=%s \n", name)
|
||||
if name == "errorSource" {
|
||||
return true, nil, fmt.Errorf("error while deleting ContainerSource source %s", name)
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
err := client.DeleteContainerSource("foo")
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.DeleteContainerSource("errorSource")
|
||||
assert.ErrorContains(t, err, "errorSource")
|
||||
}
|
||||
|
||||
func TestCreateContainerSourceSource(t *testing.T) {
|
||||
sourcesServer, client := setupFakeContainerSourcesClient()
|
||||
|
||||
sourcesServer.AddReactor("create", "containersources",
|
||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||
newSource := a.(clienttesting.CreateAction).GetObject()
|
||||
name := newSource.(metav1.Object).GetName()
|
||||
if name == "errorSource" {
|
||||
return true, nil, fmt.Errorf("error while creating ContainerSource source %s", name)
|
||||
}
|
||||
return true, newSource, nil
|
||||
})
|
||||
err := client.CreateContainerSource(newContainerSource("foo", "Event"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.CreateContainerSource(newContainerSource("errorSource", "Event"))
|
||||
assert.ErrorContains(t, err, "errorSource")
|
||||
|
||||
}
|
||||
|
||||
func TestGetContainerSource(t *testing.T) {
|
||||
sourcesServer, client := setupFakeContainerSourcesClient()
|
||||
|
||||
sourcesServer.AddReactor("get", "containersources",
|
||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||
name := a.(clienttesting.GetAction).GetName()
|
||||
if name == "errorSource" {
|
||||
return true, nil, fmt.Errorf("error while getting Container source %s", name)
|
||||
}
|
||||
return true, newContainerSource(name, "Event"), nil
|
||||
})
|
||||
testsource, err := client.GetContainerSource("foo")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, testsource.Name, "foo")
|
||||
assert.Equal(t, testsource.Spec.Sink.Ref.Name, "foosvc")
|
||||
|
||||
_, err = client.GetContainerSource("errorSource")
|
||||
assert.ErrorContains(t, err, "errorSource")
|
||||
}
|
||||
|
||||
func TestUpdateContainerSource(t *testing.T) {
|
||||
sourcesServer, client := setupFakeContainerSourcesClient()
|
||||
|
||||
sourcesServer.AddReactor("update", "containersources",
|
||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||
updatedSource := a.(clienttesting.UpdateAction).GetObject()
|
||||
name := updatedSource.(metav1.Object).GetName()
|
||||
if name == "errorSource" {
|
||||
return true, nil, fmt.Errorf("error while updating Container source %s", name)
|
||||
}
|
||||
return true, NewContainerSourceBuilderFromExisting(updatedSource.(*v1alpha2.ContainerSource)).Build(), nil
|
||||
})
|
||||
err := client.UpdateContainerSource(newContainerSource("foo", "Event"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.UpdateContainerSource(newContainerSource("errorSource", "Event"))
|
||||
assert.ErrorContains(t, err, "errorSource")
|
||||
}
|
||||
|
||||
func TestListContainerSource(t *testing.T) {
|
||||
sourcesServer, client := setupFakeContainerSourcesClient()
|
||||
|
||||
sourcesServer.AddReactor("list", "containersources",
|
||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||
cJSource := newContainerSource("testsource", "Event")
|
||||
return true, &v1alpha2.ContainerSourceList{Items: []v1alpha2.ContainerSource{*cJSource}}, nil
|
||||
})
|
||||
|
||||
sourceList, err := client.ListContainerSources()
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(sourceList.Items), 1)
|
||||
}
|
||||
|
||||
func newContainerSource(name, container string) *v1alpha2.ContainerSource {
|
||||
b := NewContainerSourceBuilder(name).
|
||||
PodSpec(corev1.PodSpec{}).
|
||||
Sink(duckv1.Destination{
|
||||
Ref: &duckv1.KReference{
|
||||
Kind: "Service",
|
||||
Name: "foosvc",
|
||||
Namespace: "default",
|
||||
}})
|
||||
|
||||
return b.Build()
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2019 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 im
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build e2e
|
||||
// +build !serving
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
"knative.dev/client/lib/test"
|
||||
"knative.dev/client/pkg/util"
|
||||
pkgtest "knative.dev/pkg/test"
|
||||
)
|
||||
|
||||
func TestSourceContainer(t *testing.T) {
|
||||
t.Parallel()
|
||||
it, err := test.NewKnTest()
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
err := it.Teardown()
|
||||
assert.NilError(t, err)
|
||||
}()
|
||||
|
||||
r := test.NewKnRunResultCollector(t, it)
|
||||
defer r.DumpIfFailed()
|
||||
|
||||
test.ServiceCreate(r, "testsvc0")
|
||||
|
||||
t.Log("create container source with a sink to a service")
|
||||
containerSourceCreate(r, "testsource0", "ksvc:testsvc0")
|
||||
containerSourceListOutputName(r, "testsource0")
|
||||
|
||||
t.Log("list container sources")
|
||||
containerSourceList(r, "testsource0")
|
||||
|
||||
t.Log("delete container sources")
|
||||
containerSourceDelete(r, "testsource0")
|
||||
|
||||
t.Log("create container source with a missing sink service")
|
||||
containerSourceCreateMissingSink(r, "testsource2", "ksvc:unknown")
|
||||
|
||||
t.Log("update container source sink service")
|
||||
containerSourceCreate(r, "testsource3", "ksvc:testsvc0")
|
||||
test.ServiceCreate(r, "testsvc1")
|
||||
containerSourceUpdateSink(r, "testsource3", "ksvc:testsvc1")
|
||||
jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}"
|
||||
out, err := test.GetResourceFieldsWithJSONPath(t, it, "containersource.sources.knative.dev", "testsource3", jpSinkRefNameInSpec)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out, "testsvc1")
|
||||
}
|
||||
|
||||
func containerSourceCreate(r *test.KnRunResultCollector, sourceName string, sink string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "create", sourceName, "--image", pkgtest.ImagePath("grpc-ping"), "--port", "h2c:8080", "--sink", sink)
|
||||
r.AssertNoError(out)
|
||||
assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "container", "source", sourceName, "created", "namespace", r.KnTest().Kn().Namespace()))
|
||||
}
|
||||
|
||||
func containerSourceListOutputName(r *test.KnRunResultCollector, containerSources ...string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "list", "--output", "name")
|
||||
r.AssertNoError(out)
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stdout, containerSources...))
|
||||
}
|
||||
|
||||
func containerSourceList(r *test.KnRunResultCollector, containerSources ...string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "list")
|
||||
r.AssertNoError(out)
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stdout, "NAME", "IMAGE", "SINK", "READY"))
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stdout, containerSources...))
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stdout, "grpc-ping", "ksvc:testsvc0"))
|
||||
}
|
||||
|
||||
func containerSourceCreateMissingSink(r *test.KnRunResultCollector, sourceName string, sink string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "create", sourceName, "--image", pkgtest.ImagePath("grpc-ping"), "--port", "h2c:8080", "--sink", sink)
|
||||
r.AssertError(out)
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stderr, "services.serving.knative.dev", "not found"))
|
||||
}
|
||||
|
||||
func containerSourceDelete(r *test.KnRunResultCollector, sourceName string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "delete", sourceName)
|
||||
r.AssertNoError(out)
|
||||
assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "container", "source", sourceName, "deleted", "namespace", r.KnTest().Kn().Namespace()))
|
||||
}
|
||||
|
||||
func containerSourceUpdateSink(r *test.KnRunResultCollector, sourceName string, sink string) {
|
||||
out := r.KnTest().Kn().Run("source", "container", "update", sourceName, "--sink", sink)
|
||||
r.AssertNoError(out)
|
||||
assert.Check(r.T(), util.ContainsAll(out.Stdout, sourceName, "updated", "namespace", r.KnTest().Kn().Namespace()))
|
||||
}
|
||||
Loading…
Reference in New Issue