Skip to content

Commit

Permalink
add support for generic callback hooks
Browse files Browse the repository at this point in the history
This patch adds support for a generic callback system into the generator
config that allows controller implementors to specify some code that
should be injected at specific named points in a template. I expect that
eventually this generic hook system will be more useful, flexible and
extensible than the hodge-podge of custom callback methods and overrides
currently in the generator config.

Here's an example of a generator config snippet that adds a piece of
custom code to be executed in the sdk_update.go.tpl right before the
code in the resource manager's `sdkUpdate` method calls the
`newUpdateRequestPayload()` function:

```yaml
resources:
  Broker:
    hooks:
      sdk_update_pre_build_request:
        code: if err := rm.requeueIfNotRunning(latest); err != nil { return nil, err }
```

Here is the snippet from the templates/pkg/resource/sdk_update.go.tpl
file that shows how we can add these generic named hooks into our
templates at various places:

```
{{- if $hookCode := .CRD.HookCode sdk_update_pre_build_request }}
{{ $hookCode }}
{{ end -}}
```

The controller implementor need only implement the little
`requeueIfNotRunning` function, with the function signature described
in the generator config code block. We no longer need to have function
signatures match for custom callback code since the function signature
for callback code is up to the dev writing the generator.yaml config
file.
  • Loading branch information
jaypipes committed Mar 2, 2021
1 parent 4c9aa10 commit b2620bc
Show file tree
Hide file tree
Showing 7 changed files with 3,496 additions and 1 deletion.
47 changes: 46 additions & 1 deletion pkg/generate/config/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ type ResourceConfig struct {
// Found and other common error types for primary resources, and thus we
// need these instructions.
Exceptions *ExceptionsConfig `json:"exceptions,omitempty"`

// Hooks is a map, keyed by the hook identifier, of instructions for the
// the code generator about a custom callback hooks that should be injected
// into the resource's manager or SDK binding code.
Hooks map[string]*HooksConfig `json:"hooks"`
// Renames identifies fields in Operations that should be renamed.
Renames *RenamesConfig `json:"renames,omitempty"`
// ListOperation contains instructions for the code generator to generate
Expand Down Expand Up @@ -71,6 +74,28 @@ type ResourceConfig struct {
ShortNames []string `json:"shortNames,omitempty"`
}

// HooksConfig instructs the code generator how to inject custom callback hooks
// at various places in the resource manager and SDK linkage code.
//
// Example usage from the AmazonMQ generator config:
//
// resources:
// Broker:
// hooks:
// sdk_update_pre_build_update_request:
// code: |
// if err := rm.requeueIfNotRunning(latest); err != nil {
// return nil, err
// }
//
// Note that the implementor of the AmazonMQ service controller for ACK should
// ensure that there is a `requeueIfNotRunning()` method implementation in
// `pkg/resource/broker`
type HooksConfig struct {
// Code is the Go code to be injected at the hook point
Code string
}

// CompareConfig informs instruct the code generator on how to compare two different
// two objects of the same type
type CompareConfig struct {
Expand Down Expand Up @@ -349,3 +374,23 @@ func (c *Config) ResourceShortNames(resourceName string) []string {
}
return rConfig.ShortNames
}

// ResourceHookCode returns a string with custom callback code for a resource
// and hook identifier
func (c *Config) ResourceHookCode(resourceName string, hookID string) string {
if resourceName == "" || hookID == "" {
return ""
}
if c == nil {
return ""
}
rConfig, ok := c.Resources[resourceName]
if !ok {
return ""
}
hook, ok := rConfig.Hooks[hookID]
if !ok {
return ""
}
return hook.Code
}
41 changes: 41 additions & 0 deletions pkg/generate/mq_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 generate_test

import (
"testing"

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

"github.com/aws-controllers-k8s/code-generator/pkg/testutil"
)

func TestMQ_HookCode(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

g := testutil.NewGeneratorForService(t, "mq")

crds, err := g.GetCRDs()
require.Nil(err)

crd := getCRDByName("Broker", crds)
require.NotNil(crd)

// The Broker's update operation has a special hook callback configured
expected := `if err := rm.requeueIfNotRunning(latest); err != nil { return nil, err }`
got := crd.HookCode("sdk_update_pre_build_request")
assert.Equal(expected, got)
}
Loading

0 comments on commit b2620bc

Please sign in to comment.