Skip to content

Commit

Permalink
Add ApiServer source update and describe commands (#556)
Browse files Browse the repository at this point in the history
* Dont return created ApiServer source object but only error

 - After ApiServer source object is created, we don't need it to pass
   around in caller function.

* Align creating ApiServer source client, removes unit tests

* Add ApiServer source update command

* Rename TestMockKnClient to TestMockKnCronJobSourceClient

* Add mock client for ApiServer Source and its tests

* Add mock unit tests for create, delete and update

* Add e2e tests for apiserver source update

 - Add a test for apiserver source sink update
 - Verify the updated sink name after the apiserver source is created
 - Update resource names in existing tests

* Uses builder pattern for ApiServer source create command

* Update ApiServer source create/update flags and required config

* Uses builder pattern for ApiServer source update command

* Align create/update/delete description and error messages

* Add unit tests for get/create/update/delete in apiserver_client.go

* Update e2e tests expected output per change in commands output

* Golint fixes, Api -> API and add exported method docs

* Rename a test method and source update command description

* Add ApiServer source describe command

 - Add command and unit tests
 - TODO for later: Add 'Controller Selector' section for --verbose
  • Loading branch information
navidshaikh authored and knative-prow-robot committed Dec 16, 2019
1 parent 7def9f4 commit 6ac25cd
Show file tree
Hide file tree
Showing 26 changed files with 1,070 additions and 292 deletions.
6 changes: 4 additions & 2 deletions docs/cmd/kn_source_apiserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ kn source apiserver [flags]
### SEE ALSO

* [kn source](kn_source.md) - Event source command group
* [kn source apiserver create](kn_source_apiserver_create.md) - Create an ApiServerSource, which watches for Kubernetes events and forwards them to a sink
* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete an ApiServerSource.
* [kn source apiserver create](kn_source_apiserver_create.md) - Create an ApiServer source.
* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete an ApiServer source.
* [kn source apiserver describe](kn_source_apiserver_describe.md) - Describe an ApiServer source.
* [kn source apiserver update](kn_source_apiserver_update.md) - Update an ApiServer source.

8 changes: 4 additions & 4 deletions docs/cmd/kn_source_apiserver_create.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## kn source apiserver create

Create an ApiServerSource, which watches for Kubernetes events and forwards them to a sink
Create an ApiServer source.

### Synopsis

Create an ApiServerSource, which watches for Kubernetes events and forwards them to a sink
Create an ApiServer source.

```
kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE [flags]
Expand All @@ -13,7 +13,7 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM
### Examples

```
# Create an ApiServerSource 'k8sevents' which consumes Kubernetes events and sends message to service 'mysvc' as a cloudevent
kn source apiserver create k8sevents --resource Event --service-account myaccountname --sink svc:mysvc
```
Expand All @@ -28,7 +28,7 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM
-n, --namespace string Specify the namespace to operate in.
--resource strings Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
"APIVersion" and "isControler" can be omitted.
"APIVersion" is "v1" by default, "isController" is "false" by default.
"APIVersion" is "v1" by default, "isController" is "false" by default.
--service-account string Name of the service account to use to run this source
-s, --sink string Addressable sink for events
```
Expand Down
4 changes: 2 additions & 2 deletions docs/cmd/kn_source_apiserver_delete.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## kn source apiserver delete

Delete an ApiServerSource.
Delete an ApiServer source.

### Synopsis

Delete an ApiServerSource.
Delete an ApiServer source.

```
kn source apiserver delete NAME [flags]
Expand Down
40 changes: 40 additions & 0 deletions docs/cmd/kn_source_apiserver_describe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## kn source apiserver describe

Describe an ApiServer source.

### Synopsis

Describe an ApiServer source.

```
kn source apiserver describe NAME [flags]
```

### Examples

```
# Describe an ApiServer source with name 'k8sevents'
kn source apiserver 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 config file (default is $HOME/.kn/config.yaml)
--kubeconfig string kubectl config file (default is $HOME/.kube/config)
--log-http log http traffic
```

### SEE ALSO

* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group

47 changes: 47 additions & 0 deletions docs/cmd/kn_source_apiserver_update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## kn source apiserver update

Update an ApiServer source.

### Synopsis

Update an ApiServer source.

```
kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE [flags]
```

### Examples

```
# Update an ApiServerSource 'k8sevents' with different service account and sink service
kn source apiserver update k8sevents --service-account newsa --sink svc:newsvc
```

### Options

```
-h, --help help for update
--mode string The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
"Resource" send the full resource. (default "Ref")
-n, --namespace string Specify the namespace to operate in.
--resource strings Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
"APIVersion" and "isControler" can be omitted.
"APIVersion" is "v1" by default, "isController" is "false" by default.
--service-account string Name of the service account to use to run this source
-s, --sink string Addressable sink for events
```

### Options inherited from parent commands

```
--config string kn config file (default is $HOME/.kn/config.yaml)
--kubeconfig string kubectl config file (default is $HOME/.kube/config)
--log-http log http traffic
```

### SEE ALSO

* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group

109 changes: 92 additions & 17 deletions pkg/eventing/sources/v1alpha1/apiserver_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,27 @@
package v1alpha1

import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kn_errors "knative.dev/client/pkg/errors"
"knative.dev/eventing/pkg/apis/sources/v1alpha1"
client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1"

kn_errors "knative.dev/client/pkg/errors"
duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
)

// Interface for working with ApiServer sources
type KnApiServerSourcesClient interface {
// KnAPIServerSourcesClient interface for working with ApiServer sources
type KnAPIServerSourcesClient interface {

// Get an ApiServerSource by name
GetAPIServerSource(name string) (*v1alpha1.ApiServerSource, error)

// Get an ApiServerSource by object
CreateApiServerSource(apisvrsrc *v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error)
// Create an ApiServerSource by object
CreateAPIServerSource(apiSource *v1alpha1.ApiServerSource) error

// Update an ApiServerSource by object
UpdateAPIServerSource(apiSource *v1alpha1.ApiServerSource) error

// Delete an ApiServerSource by name
DeleteApiServerSource(name string) error
DeleteAPIServerSource(name string) error

// Get namespace for this client
Namespace() string
Expand All @@ -43,30 +49,99 @@ type apiServerSourcesClient struct {
namespace string
}

// NewKnSourcesClient is to invoke Eventing Sources Client API to create object
func newKnApiServerSourcesClient(client client_v1alpha1.ApiServerSourceInterface, namespace string) KnApiServerSourcesClient {
// newKnAPIServerSourcesClient is to invoke Eventing Sources Client API to create object
func newKnAPIServerSourcesClient(client client_v1alpha1.ApiServerSourceInterface, namespace string) KnAPIServerSourcesClient {
return &apiServerSourcesClient{
client: client,
namespace: namespace,
}
}

//CreateApiServerSource is used to create an instance of ApiServerSource
func (c *apiServerSourcesClient) CreateApiServerSource(apisvrsrc *v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error) {
ins, err := c.client.Create(apisvrsrc)
//GetAPIServerSource returns apiSource object if present
func (c *apiServerSourcesClient) GetAPIServerSource(name string) (*v1alpha1.ApiServerSource, error) {
apiSource, err := c.client.Get(name, metav1.GetOptions{})
if err != nil {
return nil, kn_errors.GetError(err)
}
return ins, nil

return apiSource, nil
}

//CreateAPIServerSource is used to create an instance of ApiServerSource
func (c *apiServerSourcesClient) CreateAPIServerSource(apiSource *v1alpha1.ApiServerSource) error {
_, err := c.client.Create(apiSource)
if err != nil {
return kn_errors.GetError(err)
}

return nil
}

//UpdateAPIServerSource is used to update an instance of ApiServerSource
func (c *apiServerSourcesClient) UpdateAPIServerSource(apiSource *v1alpha1.ApiServerSource) error {
_, err := c.client.Update(apiSource)
if err != nil {
return kn_errors.GetError(err)
}

return nil
}

//DeleteApiServerSource is used to create an instance of ApiServerSource
func (c *apiServerSourcesClient) DeleteApiServerSource(name string) error {
err := c.client.Delete(name, &v1.DeleteOptions{})
//DeleteAPIServerSource is used to create an instance of ApiServerSource
func (c *apiServerSourcesClient) DeleteAPIServerSource(name string) error {
err := c.client.Delete(name, &metav1.DeleteOptions{})
return err
}

// Return the client's namespace
func (c *apiServerSourcesClient) Namespace() string {
return c.namespace
}

// APIServerSourceBuilder is for building the source
type APIServerSourceBuilder struct {
apiServerSource *v1alpha1.ApiServerSource
}

// NewAPIServerSourceBuilder for building ApiServer source object
func NewAPIServerSourceBuilder(name string) *APIServerSourceBuilder {
return &APIServerSourceBuilder{apiServerSource: &v1alpha1.ApiServerSource{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}}
}

// NewAPIServerSourceBuilderFromExisting for building the object from existing ApiServerSource object
func NewAPIServerSourceBuilderFromExisting(apiServerSource *v1alpha1.ApiServerSource) *APIServerSourceBuilder {
return &APIServerSourceBuilder{apiServerSource: apiServerSource.DeepCopy()}
}

// Resources which should be streamed
func (b *APIServerSourceBuilder) Resources(resources []v1alpha1.ApiServerResource) *APIServerSourceBuilder {
b.apiServerSource.Spec.Resources = resources
return b
}

// ServiceAccount with which this source should operate
func (b *APIServerSourceBuilder) ServiceAccount(sa string) *APIServerSourceBuilder {
b.apiServerSource.Spec.ServiceAccountName = sa
return b
}

// Mode for whether to send resource 'Ref' or complete 'Resource'
func (b *APIServerSourceBuilder) Mode(mode string) *APIServerSourceBuilder {
b.apiServerSource.Spec.Mode = mode
return b
}

// Sink or destination of the source
func (b *APIServerSourceBuilder) Sink(sink *duckv1beta1.Destination) *APIServerSourceBuilder {
b.apiServerSource.Spec.Sink = sink
return b
}

// Build the ApiServerSource object
func (b *APIServerSourceBuilder) Build() *v1alpha1.ApiServerSource {
return b.apiServerSource
}
109 changes: 109 additions & 0 deletions pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// 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 implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
"testing"

"knative.dev/eventing/pkg/apis/sources/v1alpha1"

"knative.dev/client/pkg/util/mock"
)

// MockKnAPIServerSourceClient for mocking the client
type MockKnAPIServerSourceClient struct {
t *testing.T
recorder *APIServerSourcesRecorder
namespace string
}

// NewMockKnAPIServerSourceClient returns a new mock instance which you need to record for
func NewMockKnAPIServerSourceClient(t *testing.T, ns ...string) *MockKnAPIServerSourceClient {
namespace := "default"
if len(ns) > 0 {
namespace = ns[0]
}
return &MockKnAPIServerSourceClient{
t: t,
recorder: &APIServerSourcesRecorder{mock.NewRecorder(t, namespace)},
}
}

// Ensure that the interface is implemented
var _ KnAPIServerSourcesClient = &MockKnAPIServerSourceClient{}

// APIServerSourcesRecorder for recording actions on source
type APIServerSourcesRecorder struct {
r *mock.Recorder
}

// Recorder returns the recorder for registering API calls
func (c *MockKnAPIServerSourceClient) Recorder() *APIServerSourcesRecorder {
return c.recorder
}

// Namespace of this client
func (c *MockKnAPIServerSourceClient) Namespace() string {
return c.recorder.r.Namespace()
}

// GetAPIServerSource records a call for GetApiServerSource with the expected object or error. Either apiServerSource or err should be nil
func (sr *APIServerSourcesRecorder) GetAPIServerSource(name interface{}, apiServerSource *v1alpha1.ApiServerSource, err error) {
sr.r.Add("GetApiServerSource", []interface{}{name}, []interface{}{apiServerSource, err})
}

// GetAPIServerSource performs a previously recorded action, failing if non has been registered
func (c *MockKnAPIServerSourceClient) GetAPIServerSource(name string) (*v1alpha1.ApiServerSource, error) {
call := c.recorder.r.VerifyCall("GetApiServerSource", name)
return call.Result[0].(*v1alpha1.ApiServerSource), mock.ErrorOrNil(call.Result[1])
}

// CreateAPIServerSource records a call for CreateApiServerSource with the expected error
func (sr *APIServerSourcesRecorder) CreateAPIServerSource(apiServerSource interface{}, err error) {
sr.r.Add("CreateApiServerSource", []interface{}{apiServerSource}, []interface{}{err})
}

// CreateAPIServerSource performs a previously recorded action, failing if non has been registered
func (c *MockKnAPIServerSourceClient) CreateAPIServerSource(apiServerSource *v1alpha1.ApiServerSource) error {
call := c.recorder.r.VerifyCall("CreateApiServerSource", apiServerSource)
return mock.ErrorOrNil(call.Result[0])
}

// UpdateAPIServerSource records a call for UpdateAPIServerSource with the expected error (nil if none)
func (sr *APIServerSourcesRecorder) UpdateAPIServerSource(apiServerSource interface{}, err error) {
sr.r.Add("UpdateAPIServerSource", []interface{}{apiServerSource}, []interface{}{err})
}

// UpdateAPIServerSource performs a previously recorded action, failing if non has been registered
func (c *MockKnAPIServerSourceClient) UpdateAPIServerSource(apiServerSource *v1alpha1.ApiServerSource) error {
call := c.recorder.r.VerifyCall("UpdateAPIServerSource", apiServerSource)
return mock.ErrorOrNil(call.Result[0])
}

// DeleteAPIServerSource records a call for DeleteAPIServerSource with the expected error (nil if none)
func (sr *APIServerSourcesRecorder) DeleteAPIServerSource(name interface{}, err error) {
sr.r.Add("DeleteAPIServerSource", []interface{}{name}, []interface{}{err})
}

// DeleteAPIServerSource performs a previously recorded action, failing if non has been registered
func (c *MockKnAPIServerSourceClient) DeleteAPIServerSource(name string) error {
call := c.recorder.r.VerifyCall("DeleteAPIServerSource", name)
return mock.ErrorOrNil(call.Result[0])
}

// Validate validates whether every recorded action has been called
func (sr *APIServerSourcesRecorder) Validate() {
sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
}
Loading

0 comments on commit 6ac25cd

Please sign in to comment.