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](kn.md) - kn manages Knative Serving and Eventing resources
|
||||||
* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources
|
* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources
|
||||||
* [kn source binding](kn_source_binding.md) - Manage sink bindings
|
* [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](kn_source_list.md) - List event sources
|
||||||
* [kn source list-types](kn_source_list-types.md) - List event source types
|
* [kn source list-types](kn_source_list-types.md) - List event source types
|
||||||
* [kn source ping](kn_source_ping.md) - Manage ping sources
|
* [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"
|
||||||
"knative.dev/client/pkg/kn/commands/source/apiserver"
|
"knative.dev/client/pkg/kn/commands/source/apiserver"
|
||||||
"knative.dev/client/pkg/kn/commands/source/binding"
|
"knative.dev/client/pkg/kn/commands/source/binding"
|
||||||
|
"knative.dev/client/pkg/kn/commands/source/container"
|
||||||
"knative.dev/client/pkg/kn/commands/source/ping"
|
"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(apiserver.NewAPIServerCommand(p))
|
||||||
sourceCmd.AddCommand(ping.NewPingCommand(p))
|
sourceCmd.AddCommand(ping.NewPingCommand(p))
|
||||||
sourceCmd.AddCommand(binding.NewBindingCommand(p))
|
sourceCmd.AddCommand(binding.NewBindingCommand(p))
|
||||||
|
sourceCmd.AddCommand(container.NewContainerCommand(p))
|
||||||
return sourceCmd
|
return sourceCmd
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,6 @@ func (p *PodSpecFlags) AddFlags(flagset *pflag.FlagSet) []string {
|
||||||
// ResolvePodSpec will create corev1.PodSpec based on the flag inputs
|
// ResolvePodSpec will create corev1.PodSpec based on the flag inputs
|
||||||
func (p *PodSpecFlags) ResolvePodSpec(podSpec *corev1.PodSpec, flags *pflag.FlagSet) error {
|
func (p *PodSpecFlags) ResolvePodSpec(podSpec *corev1.PodSpec, flags *pflag.FlagSet) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if flags.Changed("env") {
|
if flags.Changed("env") {
|
||||||
envMap, err := util.MapFromArrayAllowingSingles(p.Env, "=")
|
envMap, err := util.MapFromArrayAllowingSingles(p.Env, "=")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ type KnSourcesClient interface {
|
||||||
|
|
||||||
// Get client for ApiServer sources
|
// Get client for ApiServer sources
|
||||||
APIServerSourcesClient() KnAPIServerSourcesClient
|
APIServerSourcesClient() KnAPIServerSourcesClient
|
||||||
|
|
||||||
|
// Get client for container sources
|
||||||
|
ContainerSourcesClient() KnContainerSourcesClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// sourcesClient is a combination of Sources client interface and namespace
|
// 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)
|
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
|
// BuiltInSourcesGVKs returns the GVKs for built in sources
|
||||||
func BuiltInSourcesGVKs() []schema.GroupVersionKind {
|
func BuiltInSourcesGVKs() []schema.GroupVersionKind {
|
||||||
return []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