Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Support multi-container Providers. #79

Merged
merged 1 commit into from
Jun 6, 2024
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 Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ ENV HOME=/addon ADDON=/addon
WORKDIR /addon
ARG GOPATH=/opt/app-root
COPY --from=shim /usr/bin/windup-shim /usr/bin
COPY --from=addon $GOPATH/src/settings.json $ADDON/opt/settings.json
COPY --from=addon $GOPATH/src/settings.yaml $ADDON/opt/settings.yaml
COPY --from=addon $GOPATH/src/bin/addon /usr/bin
ENTRYPOINT ["/usr/bin/addon"]
3 changes: 3 additions & 0 deletions builder/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func (b *Deps) read() (input []output.DepsFlatItem, err error) {
input = []output.DepsFlatItem{}
f, err := os.Open(b.Path)
if err != nil {
if os.IsNotExist(err) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hint: some providers do not report deps.

err = nil
}
return
}
defer func() {
Expand Down
6 changes: 5 additions & 1 deletion cmd/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ func (r *Analyzer) options(output string) (options command.Options, err error) {
if err != nil {
return
}
settings.Report()
f, err := addon.File.Post(settings.path())
if err != nil {
return
}
addon.Attach(f)
Copy link
Contributor Author

@jortel jortel May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hint: Attach settings for cleaner activity log.

return
}

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

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

"github.com/konveyor/analyzer-lsp/provider"
"github.com/konveyor/tackle2-hub/api"
)

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

// SelectorNotSupported used to report not supported.
type SelectorNotSupported struct {
Selector string
}

func (e *SelectorNotSupported) Error() (s string) {
return fmt.Sprintf("Resource selector='%s', not-supported.", e.Selector)
}

func (e *SelectorNotSupported) Is(err error) (matched bool) {
var inst *SelectorNotSupported
matched = errors.As(err, &inst)
return
}

// FieldNotMatched used to report resource field not matched.
type FieldNotMatched struct {
Kind string
Field string
}

func (e *FieldNotMatched) Error() (s string) {
return fmt.Sprintf("Resource injector: field=%s.%s, not-matched.", e.Kind, e.Field)
}

func (e *FieldNotMatched) Is(err error) (matched bool) {
var inst *FieldNotMatched
matched = errors.As(err, &inst)
return
}

// Field injection specification.
type Field struct {
Name string `json:"name"`
Path string `json:"path"`
Key string `json:"key"`
}

// Resource injection specification.
// Format: <kind>:<key>=<value>
type Resource struct {
Selector string `json:"selector"`
Fields []Field `json:"fields"`
}

// Metadata for provider extensions.
type Metadata struct {
Resources []Resource `json:"resources,omitempty"`
Provider provider.Config `json:"provider"`
}

// ParsedSelector -
type ParsedSelector struct {
ns string
kind string
name string
value string
}

// With parses and populates the selector.
func (p *ParsedSelector) With(s string) {
part := strings.SplitN(s, "/", 2)
if len(part) > 1 {
p.ns = part[0]
s = part[1]
}
part = strings.SplitN(s, ":", 2)
if len(part) > 1 {
p.kind = part[0]
s = part[1]
}
part = strings.SplitN(s, "=", 2)
p.name = part[0]
if len(part) > 1 {
p.value = part[1]
}
}

// ResourceInjector inject resources into extension metadata.
type ResourceInjector struct {
dict map[string]string
}

// Inject resources into extension metadata.
// Returns injected provider (settings).
func (r *ResourceInjector) Inject(extension *api.Extension) (p *provider.Config, err error) {
mp := r.asMap(extension.Metadata)
md := Metadata{}
err = r.object(mp, &md)
if err != nil {
return
}
err = r.build(&md)
if err != nil {
return
}
mp = r.asMap(&md.Provider)
mp = r.inject(mp).(map[string]any)
err = r.object(mp, &md.Provider)
if err != nil {
return
}
p = &md.Provider
return
}

// build builds resource dictionary.
func (r *ResourceInjector) build(md *Metadata) (err error) {
r.dict = make(map[string]string)
application, err := addon.Task.Application()
if err != nil {
return
}
for _, resource := range md.Resources {
parsed := ParsedSelector{}
parsed.With(resource.Selector)
switch strings.ToLower(parsed.kind) {
case "identity":
identity, found, nErr := addon.Application.FindIdentity(application.ID, parsed.value)
if nErr != nil {
err = nErr
return
}
if found {
err = r.add(&resource, identity)
if err != nil {
return
}
}
default:
err = &SelectorNotSupported{Selector: resource.Selector}
return
}
}
return
}

// add the resource fields specified in the injector.
func (r *ResourceInjector) add(resource *Resource, object any) (err error) {
mp := r.asMap(object)
for _, f := range resource.Fields {
v, found := mp[f.Name]
if !found {
err = &FieldNotMatched{
Kind: resource.Selector,
Field: f.Name,
}
return
}
fv := r.string(v)
if f.Path != "" {
err = r.write(f.Path, fv)
if err != nil {
return
}
fv = f.Path
}
r.dict[f.Key] = fv
}
return
}

// write a resource field value to a file.
func (r *ResourceInjector) write(path string, s string) (err error) {
f, err := os.Create(path)
if err == nil {
_, err = f.Write([]byte(s))
_ = f.Close()
}
return
}

// string returns a string representation of a field value.
func (r *ResourceInjector) string(object any) (s string) {
if object != nil {
s = fmt.Sprintf("%v", object)
}
return
}

// objectMap returns a map for a resource object.
func (r *ResourceInjector) asMap(object any) (mp map[string]any) {
b, _ := json.Marshal(object)
mp = make(map[string]any)
_ = json.Unmarshal(b, &mp)
return
}

// objectMap returns a map for a resource object.
func (r *ResourceInjector) object(mp map[string]any, object any) (err error) {
b, _ := json.Marshal(mp)
err = json.Unmarshal(b, object)
return
}

// inject replaces `dict` variables referenced in metadata.
func (r *ResourceInjector) 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 := KeyRegex.FindStringSubmatch(node)
if len(match) < 3 {
break
}
node = strings.Replace(
node,
match[0],
r.dict[match[2]],
-1)
}
out = node
default:
out = node
}
return
}
18 changes: 15 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import (
hub "github.com/konveyor/tackle2-hub/addon"
"github.com/konveyor/tackle2-hub/api"
"github.com/konveyor/tackle2-hub/nas"
"k8s.io/utils/env"
)

var (
addon = hub.Addon
BinDir = ""
SharedDir = ""
CacheDir = ""
SourceDir = ""
Dir = ""
M2Dir = ""
Expand All @@ -28,10 +31,12 @@ var (
func init() {
Dir, _ = os.Getwd()
OptDir = path.Join(Dir, "opt")
SourceDir = path.Join(Dir, "source")
BinDir = path.Join(Dir, "bin")
SharedDir = env.GetString(hub.EnvSharedDir, "/tmp/shared")
CacheDir = env.GetString(hub.EnvCacheDir, "/tmp/cache")
SourceDir = path.Join(SharedDir, "source")
RuleDir = path.Join(Dir, "rules")
M2Dir = "/cache/m2"
BinDir = path.Join(SharedDir, "bin")
M2Dir = path.Join(CacheDir, "m2")
}

// Data Addon data passed in the secret.
Expand All @@ -51,6 +56,13 @@ type Data struct {
// main
func main() {
addon.Run(func() (err error) {
addon.Activity("OptDir: %s", OptDir)
addon.Activity("SharedDir: %s", SharedDir)
addon.Activity("CacheDir: %s", CacheDir)
addon.Activity("SourceDir: %s", SourceDir)
addon.Activity("RuleDir: %s", RuleDir)
addon.Activity("BinDir: %s", BinDir)
addon.Activity("M2Dir: %s", M2Dir)
//
// Get the addon data associated with the task.
d := &Data{}
Expand Down
13 changes: 0 additions & 13 deletions cmd/mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ type Mode struct {
path struct {
appDir string
binary string
maven struct {
settings string
}
}
}

Expand All @@ -39,15 +36,6 @@ func (r *Mode) Build(application *api.Application) (err error) {
Identities: application.Identities,
},
}
path, err := maven.CreateSettingsFile()
if err != nil {
return err
}
r.path.maven.settings = path
addon.Activity(
"[MVN] Using settings file(path=%v).",
path)

if !r.Binary {
err = r.fetchRepository(application)
return
Expand All @@ -67,7 +55,6 @@ func (r *Mode) Build(application *api.Application) (err error) {

// AddOptions adds analyzer options.
func (r *Mode) AddOptions(options *command.Options, settings *Settings) (err error) {
settings.MavenSettings(r.path.maven.settings)
if r.WithDeps {
settings.Mode(provider.FullAnalysisMode)
} else {
Expand Down
Loading
Loading