Skip to content

Commit

Permalink
feat: Removed usage of redundant GVR fields in k8s/workflow triggers (a…
Browse files Browse the repository at this point in the history
…rgoproj#1333)

* removed usage of redundent group,version,resource fields in k8s/workflow triggers

Signed-off-by: Daniel Soifer <[email protected]>

* fix

Signed-off-by: Daniel Soifer <[email protected]>
  • Loading branch information
daniel-codefresh authored Sep 5, 2021
1 parent f763e68 commit 24ef7c6
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 36 deletions.
8 changes: 2 additions & 6 deletions controllers/sensor/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,7 @@ func validateK8STrigger(trigger *v1alpha1.StandardK8STrigger) error {
if trigger.Source == nil {
return errors.New("k8s trigger does not contain an absolute action")
}
if trigger.GroupVersionResource.Size() == 0 {
return errors.New("must provide group, version and resource for the resource")
}

switch trigger.Operation {
case "", v1alpha1.Create, v1alpha1.Patch, v1alpha1.Update, v1alpha1.Delete:

Expand All @@ -190,9 +188,7 @@ func validateArgoWorkflowTrigger(trigger *v1alpha1.ArgoWorkflowTrigger) error {
if trigger.Source == nil {
return errors.New("argoWorkflow trigger does not contain an absolute action")
}
if trigger.GroupVersionResource.Size() == 0 {
return errors.New("must provide group, version and resource for the resource")
}

switch trigger.Operation {
case v1alpha1.Submit, v1alpha1.Suspend, v1alpha1.Retry, v1alpha1.Resume, v1alpha1.Resubmit, v1alpha1.Terminate:
default:
Expand Down
2 changes: 1 addition & 1 deletion docs/quick_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Note: You will need to have [Argo Workflows](https://argoproj.github.io/argo-wor

1. Create webhook sensor.

kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/stable/examples/sensors/webhook.yaml
kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/master/examples/sensors/webhook-shortened.yaml

Once the sensor object is created, sensor controller will create corresponding pod and a service.

Expand Down
43 changes: 43 additions & 0 deletions examples/sensors/special-workflow-trigger-shortened.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: webhook
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: test-dep
eventSourceName: webhook
eventName: example
triggers:
- template:
name: argo-workflow-trigger
argoWorkflow:
operation: submit
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: special-trigger
spec:
entrypoint: whalesay
arguments:
parameters:
- name: message
# the value will get overridden by event payload from test-dep
value: hello world
templates:
- name: whalesay
inputs:
parameters:
- name: message
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["{{inputs.parameters.message}}"]
parameters:
- src:
dependencyName: test-dep
dataKey: body
dest: spec.arguments.parameters.0.value
62 changes: 62 additions & 0 deletions examples/sensors/trigger-standard-k8s-resource-shortened.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: webhook
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: test-dep
eventSourceName: webhook
eventName: example
triggers:
- template:
name: webhook-pod-trigger
k8s:
operation: create
source:
resource:
apiVersion: v1
kind: Pod
metadata:
generateName: hello-world-
spec:
containers:
- name: hello-container
args:
- "hello-world"
command:
- cowsay
image: "docker/whalesay:latest"
parameters:
- src:
dependencyName: test-dep
dataKey: body
dest: spec.containers.0.args.0
# - template:
# name: webhook-deployment-trigger
# k8s:
# operation: create
# source:
# resource:
# apiVersion: apps/v1
# kind: Deployment
# metadata:
# generateName: hello-world-
# spec:
# replicas: 1
# selector:
# matchLabels:
# app: mydeploy
# template:
# metadata:
# labels:
# app: mydeploy
# spec:
# containers:
# - name: hello-container
# args:
# - "hello world"
# command:
# - cowsay
# image: "docker/whalesay:latest"
43 changes: 43 additions & 0 deletions examples/sensors/webhook-shortened.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: webhook
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: test-dep
eventSourceName: webhook
eventName: example
triggers:
- template:
name: webhook-workflow-trigger
k8s:
operation: create
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: webhook-
spec:
entrypoint: whalesay
arguments:
parameters:
- name: message
# the value will get overridden by event payload from test-dep
value: hello world
templates:
- name: whalesay
inputs:
parameters:
- name: message
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["{{inputs.parameters.message}}"]
parameters:
- src:
dependencyName: test-dep
dataKey: body
dest: spec.arguments.parameters.0.value
3 changes: 3 additions & 0 deletions sensors/triggers/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func FetchKubernetesResource(source *v1alpha1.ArtifactLocation) (*unstructured.U
if err != nil {
return nil, err
}

// uObj will either hold the resource definition stored in the trigger or just
// a stub to provide enough information to fetch the object from K8s cluster
uObj, err := artifacts.FetchArtifact(reader)
if err != nil {
return nil, err
Expand Down
36 changes: 7 additions & 29 deletions sensors/triggers/standard-k8s/standar-k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
Expand All @@ -38,7 +37,6 @@ import (
"github.com/argoproj/argo-events/common/logging"
apicommon "github.com/argoproj/argo-events/pkg/apis/common"
"github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1"
"github.com/argoproj/argo-events/sensors/artifacts"
"github.com/argoproj/argo-events/sensors/policy"
"github.com/argoproj/argo-events/sensors/triggers"
)
Expand Down Expand Up @@ -83,32 +81,15 @@ func (k8sTrigger *StandardK8sTrigger) GetTriggerType() apicommon.TriggerType {
// FetchResource fetches the trigger resource from external source
func (k8sTrigger *StandardK8sTrigger) FetchResource(ctx context.Context) (interface{}, error) {
trigger := k8sTrigger.Trigger
if trigger.Template.K8s.Source == nil {
return nil, errors.Errorf("trigger source for k8s is empty")
}
creds, err := artifacts.GetCredentials(trigger.Template.K8s.Source)
if err != nil {
return nil, err
}
reader, err := artifacts.GetArtifactReader(trigger.Template.K8s.Source, creds)
if err != nil {
return nil, err
}

var rObj runtime.Object

// uObj will either hold the resource definition stored in the trigger or just
// a stub to provide enough information to fetch the object from K8s cluster
uObj, err := artifacts.FetchArtifact(reader)
uObj, err := triggers.FetchKubernetesResource(trigger.Template.K8s.Source)
if err != nil {
return nil, err
}

k8sTrigger.namespableDynamicClient = k8sTrigger.DynamicClient.Resource(schema.GroupVersionResource{
Group: trigger.Template.K8s.GroupVersionResource.Group,
Version: trigger.Template.K8s.GroupVersionResource.Version,
Resource: trigger.Template.K8s.GroupVersionResource.Resource,
})
gvr := triggers.GetGroupVersionResource(uObj)
k8sTrigger.namespableDynamicClient = k8sTrigger.DynamicClient.Resource(gvr)

if trigger.Template.K8s.LiveObject && trigger.Template.K8s.Operation == v1alpha1.Update {
objName := uObj.GetName()
Expand All @@ -117,7 +98,7 @@ func (k8sTrigger *StandardK8sTrigger) FetchResource(ctx context.Context) (interf
}

objNamespace := uObj.GetNamespace()
_, isClusterResource := clusterResources[trigger.Template.K8s.GroupVersionResource.Resource]
_, isClusterResource := clusterResources[gvr.Resource]
if objNamespace == "" && !isClusterResource {
return nil, fmt.Errorf("resource namespace must be specified for fetching live object")
}
Expand Down Expand Up @@ -152,8 +133,9 @@ func (k8sTrigger *StandardK8sTrigger) Execute(ctx context.Context, events map[st
return nil, errors.New("failed to interpret the trigger resource")
}

gvr := triggers.GetGroupVersionResource(obj)
namespace := ""
if _, isClusterResource := clusterResources[trigger.Template.K8s.GroupVersionResource.Resource]; !isClusterResource {
if _, isClusterResource := clusterResources[gvr.Resource]; !isClusterResource {
namespace = obj.GetNamespace()
// Defaults to sensor's namespace
if namespace == "" {
Expand All @@ -169,11 +151,7 @@ func (k8sTrigger *StandardK8sTrigger) Execute(ctx context.Context, events map[st

// We might have a client from FetchResource() already, or we might not have one yet.
if k8sTrigger.namespableDynamicClient == nil {
k8sTrigger.namespableDynamicClient = k8sTrigger.DynamicClient.Resource(schema.GroupVersionResource{
Group: trigger.Template.K8s.GroupVersionResource.Group,
Version: trigger.Template.K8s.GroupVersionResource.Version,
Resource: trigger.Template.K8s.GroupVersionResource.Resource,
})
k8sTrigger.namespableDynamicClient = k8sTrigger.DynamicClient.Resource(gvr)
}

switch op {
Expand Down
34 changes: 34 additions & 0 deletions sensors/triggers/triggers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright 2020 BlackRock, Inc.
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 triggers

import (
"fmt"
"strings"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)

func GetGroupVersionResource(obj *unstructured.Unstructured) schema.GroupVersionResource {
gvk := obj.GroupVersionKind()
return schema.GroupVersionResource{
Group: gvk.Group,
Version: gvk.Version,
Resource: fmt.Sprintf("%ss", strings.ToLower(gvk.Kind)),
}
}
35 changes: 35 additions & 0 deletions sensors/triggers/triggers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright 2020 BlackRock, Inc.
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 triggers

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetGroupVersionResource(t *testing.T) {
deployment := newUnstructured("apps/v1", "Deployment", "fake", "test")
expectedGVR := schema.GroupVersionResource{
Group: "apps",
Version: "v1",
Resource: "deployments",
}
result := GetGroupVersionResource(deployment)
assert.Equal(t, expectedGVR, result)
}

0 comments on commit 24ef7c6

Please sign in to comment.