Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type Handler struct {
// Fill me
}

func (h *Handler) Handle(ctx types.Context, event types.Event) []types.Action {
func (h *Handler) Handle(ctx types.Context, event types.Event) error {
// Change me
switch o := event.Object.(type) {
case *apps_v1.Deployment:
Expand Down
2 changes: 1 addition & 1 deletion pkg/generator/handler_tmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type Handler struct {
// Fill me
}

func (h *Handler) Handle(ctx types.Context, event types.Event) []types.Action {
func (h *Handler) Handle(ctx types.Context, event types.Event) error {
// Change me
switch o := event.Object.(type) {
case *apps_v1.Deployment:
Expand Down
108 changes: 47 additions & 61 deletions pkg/sdk/action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,105 +20,91 @@ import (
"github.com/coreos/operator-sdk/pkg/k8sclient"
sdkTypes "github.com/coreos/operator-sdk/pkg/sdk/types"
"github.com/coreos/operator-sdk/pkg/util/k8sutil"

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
// Supported function types
KubeApplyFunc sdkTypes.FuncType = "kube-apply"
KubeDeleteFunc sdkTypes.FuncType = "kube-delete"
)
// Create creates the provided object on the server and updates the arg
// "object" with the result from the server(UID, resourceVersion, etc).
// Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name/GenerateName, Namespace) is missing or incorrect.
// Can also return an api error from the server
// e.g AlreadyExists https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L423
func Create(object sdkTypes.Object) (err error) {
_, namespace, err := k8sutil.GetNameAndNamespace(object)
if err != nil {
return err
}
gvk := object.GetObjectKind().GroupVersionKind()
apiVersion, kind := gvk.ToAPIVersionAndKind()

var (
// kubeFuncs is the mapping of the supported functions
kubeFuncs = map[sdkTypes.FuncType]sdkTypes.KubeFunc{
KubeApplyFunc: KubeApply,
KubeDeleteFunc: KubeDelete,
resourceClient, _, err := k8sclient.GetResourceClient(apiVersion, kind, namespace)
if err != nil {
return fmt.Errorf("failed to get resource client: %v", err)
}
)

// ProcessAction invokes the function specified by action.Func
func ProcessAction(action sdkTypes.Action) error {
kubeFunc, ok := kubeFuncs[action.Func]
if !ok {
return fmt.Errorf("failed to process action: unsupported function (%v)", action.Func)
unstructObj := k8sutil.UnstructuredFromRuntimeObject(object)
unstructObj, err = resourceClient.Create(unstructObj)
if err != nil {
return err
}
err := kubeFunc(action.Object)

// Update the arg object with the result
err = k8sutil.UnstructuredIntoRuntimeObject(unstructObj, object)
if err != nil {
return fmt.Errorf("failed to process action: %v", err)
return fmt.Errorf("failed to unmarshal the retrieved data: %v", err)
}
return nil
}

// KubeApply tries to create the specified object or update it if it already exists
func KubeApply(object sdkTypes.Object) (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("kube-apply failed: %v", err)
}
}()

name, namespace, err := k8sutil.GetNameAndNamespace(object)
// Update updates the provided object on the server and updates the arg
// "object" with the result from the server(UID, resourceVersion, etc).
// Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name, Namespace) is missing or incorrect.
// Can also return an api error from the server
// e.g Conflict https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L428
func Update(object sdkTypes.Object) (err error) {
_, namespace, err := k8sutil.GetNameAndNamespace(object)
if err != nil {
return err
}
gvk := object.GetObjectKind().GroupVersionKind()
apiVersion, kind := gvk.ToAPIVersionAndKind()
objectInfo := k8sutil.ObjectInfo(kind, name, namespace)

resourceClient, _, err := k8sclient.GetResourceClient(apiVersion, kind, namespace)
if err != nil {
return fmt.Errorf("failed to get resource client for object: %v", err)
return fmt.Errorf("failed to get resource client: %v", err)
}

unstructObj := k8sutil.UnstructuredFromRuntimeObject(object)

// Create the resource if it doesn't exist
_, err = resourceClient.Create(unstructObj)
if err == nil {
return nil
}
if err != nil && !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create object (%s): %v ", objectInfo, err)
unstructObj, err = resourceClient.Update(unstructObj)
if err != nil {
return err
}

// Update it if it already exists
// NOTE: The update could fail if there is a resourceVersion conflict.
// That means the object is stale, and the user needs to retry the Action with
// an updated object that has the latest resourceVersion
_, err = resourceClient.Update(unstructObj)
// Update the arg object with the result
err = k8sutil.UnstructuredIntoRuntimeObject(unstructObj, object)
if err != nil {
return fmt.Errorf("failed to update object (%s): %v ", objectInfo, err)
return fmt.Errorf("failed to unmarshal the retrieved data: %v", err)
}
return nil
}

// KubeDelete deletes an object if it still exists
func KubeDelete(object sdkTypes.Object) (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("kube-delete failed: %v", err)
}
}()

// Delete deletes the specified object
// Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name, Namespace) is missing or incorrect.
// e.g NotFound https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L418
// “opts” configures the DeleteOptions
// When passed WithDeleteOptions(o), the specified metav1.DeleteOptions are set.
func Delete(object sdkTypes.Object, opts ...DeleteOption) (err error) {
name, namespace, err := k8sutil.GetNameAndNamespace(object)
if err != nil {
return err
}
gvk := object.GetObjectKind().GroupVersionKind()
apiVersion, kind := gvk.ToAPIVersionAndKind()
objectInfo := k8sutil.ObjectInfo(kind, name, namespace)

resourceClient, _, err := k8sclient.GetResourceClient(apiVersion, kind, namespace)
if err != nil {
return fmt.Errorf("failed to get resource client for object: %v", err)
return fmt.Errorf("failed to get resource client: %v", err)
}

err = resourceClient.Delete(name, &metav1.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to delete object (%s): %v", objectInfo, err)
}
return nil
o := NewDeleteOp()
o.applyOpts(opts)
return resourceClient.Delete(name, o.metaDeleteOptions)
}
110 changes: 0 additions & 110 deletions pkg/sdk/action/api.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/sdk/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
// If any intended action failed, the event would be re-triggered.
// For actions done before the failed action, there is no rollback.
type Handler interface {
Handle(sdkTypes.Context, sdkTypes.Event) []sdkTypes.Action
Handle(sdkTypes.Context, sdkTypes.Event) error
}

var (
Expand Down
11 changes: 1 addition & 10 deletions pkg/sdk/informer/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package informer

import (
sdkAction "github.com/coreos/operator-sdk/pkg/sdk/action"
sdkHandler "github.com/coreos/operator-sdk/pkg/sdk/handler"
sdkTypes "github.com/coreos/operator-sdk/pkg/sdk/types"
"github.com/coreos/operator-sdk/pkg/util/k8sutil"
Expand Down Expand Up @@ -78,16 +77,8 @@ func (i *informer) sync(key string) error {
}

sdkCtx := sdkTypes.Context{Context: i.context}
actions := sdkHandler.RegisteredHandler.Handle(sdkCtx, event)
// TODO: Add option to prevent multiple informers from invoking Handle() concurrently?

for _, action := range actions {
err := sdkAction.ProcessAction(action)
if err != nil {
return err
}
}
return nil
return sdkHandler.RegisteredHandler.Handle(sdkCtx, event)
}

// handleErr checks if an error happened and makes sure we will retry later.
Expand Down
12 changes: 0 additions & 12 deletions pkg/sdk/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,3 @@ type Event struct {
type Context struct {
Context context.Context
}

// FuncType defines the type of the function of an Action.
type FuncType string

// KubeFunc is the function signature for supported kubernetes functions
type KubeFunc func(Object) error

// Action defines what Function to apply on a given Object.
type Action struct {
Object Object
Func FuncType
}