Skip to content

Commit

Permalink
Support extensions; task kinds; multi-container task pods for providers.
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel committed May 31, 2024
1 parent e1fa5f6 commit a79b9b2
Show file tree
Hide file tree
Showing 45 changed files with 6,941 additions and 728 deletions.
8 changes: 8 additions & 0 deletions addon/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ var (
Log = logr.WithName("addon")
)

// Environment.
const (
EnvSharedDir = settings.EnvSharedPath
EnvCacheDir = settings.EnvCachePath
EnvToken = settings.EnvHubToken
EnvTask = settings.EnvTask
)

// Addon An addon adapter configured for a task execution.
var Addon *Adapter

Expand Down
76 changes: 76 additions & 0 deletions addon/injector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package addon

import (
"encoding/json"
"os"
"regexp"
"strings"

"github.com/konveyor/tackle2-hub/api"
"github.com/konveyor/tackle2-hub/task"
)

var (
EnvRegex = regexp.MustCompile(`(\$\()([^)]+)(\))`)
)

// EnvInjector inject key into extension metadata.
type EnvInjector struct {
env map[string]string
dict map[string]string
}

// Inject inject into extension metadata.
func (r *EnvInjector) Inject(extension *api.Extension) {
r.buildEnv(extension)
mp := make(map[string]any)
b, _ := json.Marshal(extension.Metadata)
_ = json.Unmarshal(b, &mp)
mp = r.inject(mp).(map[string]any)
extension.Metadata = mp
}

// buildEnv builds the extension `env`.
func (r *EnvInjector) buildEnv(extension *api.Extension) {
r.env = make(map[string]string)
for _, env := range extension.Container.Env {
key := task.ExtEnv(extension.Name, env.Name)
r.env[env.Name] = os.Getenv(key)
}
}

// inject replaces both `dict` keys and `env` environment
// variables referenced in metadata.
func (r *EnvInjector) inject(in any) (out any) {
switch node := in.(type) {
case map[string]any:
for k, v := range node {
node[k] = r.inject(v)
}
out = node
case []any:
var injected []any
for _, n := range node {
injected = append(
injected,
r.inject(n))
}
out = injected
case string:
for {
match := EnvRegex.FindStringSubmatch(node)
if len(match) < 3 {
break
}
node = strings.Replace(
node,
match[0],
r.env[match[2]],
-1)
}
out = node
default:
out = node
}
return
}
56 changes: 44 additions & 12 deletions addon/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,48 @@ func (h *Task) Application() (r *api.Application, err error) {
return
}

// Addon returns the addon associated with the task.
// The extensions are filtered to include those specified in the task.
// inject: perform injection.
func (h *Task) Addon(inject bool) (r *api.Addon, err error) {
name := h.task.Addon
if name == "" {
err = &NotFound{}
return
}
r, err = h.richClient.Addon.Get(name)
if err != nil {
return
}
// filter
included := map[string]int{}
for _, name := range h.task.Extensions {
included[name] = 0
}
var extensions []api.Extension
for i := range r.Extensions {
extension := r.Extensions[i]
if _, found := included[extension.Name]; found {
extensions = append(
extensions,
extension)
}
}
r.Extensions = extensions
// inject
if inject {
for i := range r.Extensions {
extension := &r.Extensions[i]
injector := EnvInjector{}
injector.Inject(extension)
}
}
return
}

// Data returns the addon data.
func (h *Task) Data() (d map[string]interface{}) {
d = h.task.Data.(map[string]interface{})
func (h *Task) Data() (d api.Map) {
d = h.task.Data
return
}

Expand All @@ -55,11 +94,6 @@ func (h *Task) DataWith(object interface{}) (err error) {
return
}

// Variant returns the task variant.
func (h *Task) Variant() string {
return h.task.Variant
}

// Started report addon started.
func (h *Task) Started() {
h.deleteReport()
Expand Down Expand Up @@ -169,10 +203,8 @@ func (h *Task) AttachAt(f *api.File, activity int) {
h.report.Attached,
api.Attachment{
Activity: activity,
Ref: api.Ref{
ID: f.ID,
Name: f.Name,
},
ID: f.ID,
Name: f.Name,
})
h.pushReport()
return
Expand Down Expand Up @@ -215,7 +247,7 @@ func (h *Task) Bucket() (b *binding.BucketContent) {
}

// Result report addon result.
func (h *Task) Result(object interface{}) {
func (h *Task) Result(object api.Map) {
h.report.Result = object
h.pushReport()
Log.Info("Addon reported: result.")
Expand Down
54 changes: 49 additions & 5 deletions api/addon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package api

import (
"context"
"encoding/json"
"net/http"

"github.com/gin-gonic/gin"
crd "github.com/konveyor/tackle2-hub/k8s/api/tackle/v1alpha1"
core "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
k8s "sigs.k8s.io/controller-runtime/pkg/client"
)
Expand Down Expand Up @@ -57,8 +59,19 @@ func (h AddonHandler) Get(ctx *gin.Context) {
return
}
}
extensions := &crd.ExtensionList{}
err = h.Client(ctx).List(
context.TODO(),
extensions,
&k8s.ListOptions{
Namespace: Settings.Namespace,
})
if err != nil {
_ = ctx.Error(err)
return
}
r := Addon{}
r.With(addon)
r.With(addon, extensions.Items...)

h.Respond(ctx, http.StatusOK, r)
}
Expand Down Expand Up @@ -94,12 +107,43 @@ func (h AddonHandler) List(ctx *gin.Context) {

// Addon REST resource.
type Addon struct {
Name string `json:"name"`
Image string `json:"image"`
Name string `json:"name"`
Container core.Container `json:"container"`
Extensions []Extension `json:"extensions,omitempty"`
Metadata any `json:"metadata,omitempty"`
}

// With model.
func (r *Addon) With(m *crd.Addon) {
func (r *Addon) With(m *crd.Addon, extensions ...crd.Extension) {
r.Name = m.Name
r.Image = m.Spec.Image
r.Container = m.Spec.Container
if m.Spec.Metadata.Raw != nil {
_ = json.Unmarshal(m.Spec.Metadata.Raw, &r.Metadata)
}
for i := range extensions {
extension := Extension{}
extension.With(&extensions[i])
r.Extensions = append(
r.Extensions,
extension)
}
}

// Extension REST resource.
type Extension struct {
Name string `json:"name"`
Addon string `json:"addon"`
Capabilities []string `json:"capabilities,omitempty"`
Container core.Container `json:"container"`
Metadata any `json:"metadata,omitempty"`
}

// With model.
func (r *Extension) With(m *crd.Extension) {
r.Name = m.Name
r.Addon = m.Spec.Addon
r.Container = m.Spec.Container
if m.Spec.Metadata.Raw != nil {
_ = json.Unmarshal(m.Spec.Metadata.Raw, &r.Metadata)
}
}
16 changes: 0 additions & 16 deletions api/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,19 +461,3 @@ func (r *Cursor) pageLimited() (b bool) {
b = r.Index > int64(r.Limit)
return
}

// StrMap returns a map[string]any.
// The YAML decoder can produce map[any]any which is not valid for json.
// Converts map[any]any to map[string]any as needed.
func StrMap(in any) (out any) {
out = in
if d, cast := in.(map[any]any); cast {
mp := make(map[string]any)
for k, v := range d {
s := fmt.Sprintf("%v", k)
mp[s] = StrMap(v)
}
out = mp
}
return
}
3 changes: 3 additions & 0 deletions api/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/gin-gonic/gin"
"github.com/konveyor/tackle2-hub/auth"
tasking "github.com/konveyor/tackle2-hub/task"
"gorm.io/gorm"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand All @@ -22,6 +23,8 @@ type Context struct {
Client client.Client
// Response
Response Response
// Task manager.
TaskManager *tasking.Manager
}

// Response values.
Expand Down
10 changes: 10 additions & 0 deletions api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/konveyor/tackle2-hub/api/filter"
"github.com/konveyor/tackle2-hub/api/sort"
"github.com/konveyor/tackle2-hub/model"
tasking "github.com/konveyor/tackle2-hub/task"
"github.com/mattn/go-sqlite3"
"gorm.io/gorm"
)
Expand Down Expand Up @@ -173,6 +174,15 @@ func ErrorHandler() gin.HandlerFunc {
return
}

if errors.Is(err, &tasking.BadRequest{}) {
rtx.Respond(
http.StatusBadRequest,
gin.H{
"error": err.Error(),
})
return
}

rtx.Respond(
http.StatusInternalServerError,
gin.H{
Expand Down
Loading

0 comments on commit a79b9b2

Please sign in to comment.