Skip to content

Commit

Permalink
Merge pull request #231 from wttech/osgi-component-check-v2
Browse files Browse the repository at this point in the history
OSGi component check v2
  • Loading branch information
krystian-panek-vmltech authored Jan 11, 2024
2 parents 126b31d + 6a9bda3 commit 37cfa87
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 44 deletions.
2 changes: 1 addition & 1 deletion cmd/aem/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (c *CLI) instanceDeleteCmd() *cobra.Command {
func (c *CLI) instanceAwaitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "await",
Aliases: []string{"wait"},
Aliases: []string{"wait", "check"},
Short: "Awaits stable AEM instance(s)",
Run: func(cmd *cobra.Command, args []string) {
doneThreshold, _ := cmd.Flags().GetInt("done-threshold")
Expand Down
11 changes: 8 additions & 3 deletions examples/docker/src/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,14 @@ instance:
# OSGi components state tracking
component_stable:
skip: false
pids_ignored: []
pids_failed_activation: []
pids_unsatisfied_reference: []
pids:
include: []
exclude: []
match:
"disabled": []
"no config": []
"unsatisfied (reference)": []
"satisfied": []
# Sling Installer tracking
installer:
skip: false
Expand Down
6 changes: 3 additions & 3 deletions pkg/cfg/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func (c *Config) setDefaults() {
v.SetDefault("instance.check.event_stable.details_ignored", []string{"*.*MBean", "org.osgi.service.component.runtime.ServiceComponentRuntime", "java.util.ResourceBundle"})

v.SetDefault("instance.check.component_stable.skip", false)
v.SetDefault("instance.check.component_stable.pids_ignored", []string{})
v.SetDefault("instance.check.component_stable.pids_failed_activation", []string{})
v.SetDefault("instance.check.component_stable.pids_unsatisfied_reference", []string{})
v.SetDefault("instance.check.component_stable.pids.include", []string{})
v.SetDefault("instance.check.component_stable.pids.exclude", []string{})
v.SetDefault("instance.check.component_stable.pids.match", map[string][]string{})

v.SetDefault("instance.check.installer.skip", false)
v.SetDefault("instance.check.installer.state", true)
Expand Down
87 changes: 61 additions & 26 deletions pkg/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/wttech/aemc/pkg/common/stringsx"
inst "github.com/wttech/aemc/pkg/instance"
"github.com/wttech/aemc/pkg/osgi"
"golang.org/x/exp/maps"
"io"
"strings"
"time"
Expand Down Expand Up @@ -188,7 +189,6 @@ func (c EventStableChecker) Check(_ CheckContext, instance Instance) CheckResult
return true
})
unstableEventCount := len(unstableEvents)

if unstableEventCount > 0 {
message := fmt.Sprintf("some events unstable (%d): '%s'", unstableEventCount, unstableEvents[0].Details())
return CheckResult{
Expand All @@ -204,20 +204,26 @@ func (c EventStableChecker) Check(_ CheckContext, instance Instance) CheckResult
}

type ComponentStableChecker struct {
Skip bool
PIDsIgnored []string
PIDsFailedActivation []string
PIDsUnsatisfiedReference []string
Skip bool
PIDs ComponentStablePIDs
}

type ComponentStablePIDs struct {
Include []string
Exclude []string
Match map[string][]string
}

func NewComponentStableChecker(opts *CheckOpts) ComponentStableChecker {
cv := opts.manager.aem.config.Values()

return ComponentStableChecker{
Skip: cv.GetBool("instance.check.component_stable.skip"),
PIDsIgnored: cv.GetStringSlice("instance.check.component_stable.pids_ignored"),
PIDsFailedActivation: cv.GetStringSlice("instance.check.component_stable.pids_failed_activation"),
PIDsUnsatisfiedReference: cv.GetStringSlice("instance.check.component_stable.pids_unsatisfied_reference"),
Skip: cv.GetBool("instance.check.component_stable.skip"),
PIDs: ComponentStablePIDs{
Include: cv.GetStringSlice("instance.check.component_stable.pids.include"),
Exclude: cv.GetStringSlice("instance.check.component_stable.pids.exclude"),
Match: cv.GetStringMapStringSlice("instance.check.component_stable.pids.match"),
},
}
}

Expand All @@ -235,27 +241,56 @@ func (c ComponentStableChecker) Check(_ CheckContext, instance Instance) CheckRe
}
}

failedComponents := lo.Filter(components.List, func(component osgi.ComponentListItem, _ int) bool {
return !inst.MatchSome(instance.ID(), component.PID, c.PIDsIgnored) && inst.MatchSome(instance.ID(), component.PID, c.PIDsFailedActivation) && component.State == osgi.ComponentStateFailedActivation
includedComponents := lo.Filter(components.List, func(component osgi.ComponentListItem, _ int) bool {
return inst.MatchSome(instance.ID(), component.PID, c.PIDs.Include) && !inst.MatchSome(instance.ID(), component.PID, c.PIDs.Exclude)
})
failedComponentCount := len(failedComponents)
if failedComponentCount > 0 {
message := fmt.Sprintf("some components failed activation (%d): '%s'", failedComponentCount, failedComponents[0].PID)
return CheckResult{
ok: false,
message: message,

implicitActive := !lo.Contains(maps.Keys(c.PIDs.Match), osgi.ComponentStateActive)
var implicitActiveComponents map[string]osgi.ComponentListItem
if implicitActive {
implicitActiveComponents = make(map[string]osgi.ComponentListItem)
for _, component := range includedComponents {
implicitActiveComponents[component.PID] = component
}
}

unsatisfiedComponents := lo.Filter(components.List, func(component osgi.ComponentListItem, _ int) bool {
return !inst.MatchSome(instance.ID(), component.PID, c.PIDsIgnored) && inst.MatchSome(instance.ID(), component.PID, c.PIDsUnsatisfiedReference) && component.State == osgi.ComponentStateUnsatisfiedReference
})
unsatisfiedComponentCount := len(unsatisfiedComponents)
if unsatisfiedComponentCount > 0 {
message := fmt.Sprintf("some components unsatisfied (%d): '%s'", unsatisfiedComponentCount, unsatisfiedComponents[0].PID)
return CheckResult{
ok: false,
message: message,
pidsMatched := maps.Keys(c.PIDs.Match)
// sort.Strings(pidsMatched) // stable order for better readability

for _, state := range pidsMatched {
for _, component := range includedComponents {
statePIDs := c.PIDs.Match[state]
var stateComponents []osgi.ComponentListItem
if inst.MatchSome(instance.ID(), component.PID, statePIDs) {
if component.State != state {
stateComponents = append(stateComponents, component)
}
if implicitActive {
delete(implicitActiveComponents, component.PID)
}
}
stateComponentCount := len(stateComponents)
if stateComponentCount > 0 {
stateComponentRandom := lox.Random(stateComponents)
return CheckResult{
ok: false,
message: fmt.Sprintf("components state not matching '%s' (%d): '%s'", state, stateComponentCount, stateComponentRandom.PID),
}
}
}
}

if implicitActive {
inactiveComponents := lo.Filter(maps.Values(implicitActiveComponents), func(component osgi.ComponentListItem, _ int) bool {
return component.State != osgi.ComponentStateActive
})
inactiveComponentCount := len(inactiveComponents)
if inactiveComponentCount > 0 {
inactiveComponentRandom := lox.Random(inactiveComponents)
return CheckResult{
ok: false,
message: fmt.Sprintf("components not active (%d): '%s'", inactiveComponentCount, inactiveComponentRandom.PID),
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/common/lox/lox.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ func SerialMap[I any, R any](iterable []I, callback func(iteratee I) (R, error))
return results, nil
}

var random = rand.New(rand.NewSource(time.Now().UnixNano()))

func Random[I any](iterable []I) I {
if len(iterable) == 0 {
panic("cannot get random value from empty slice")
}
rand.Seed(time.Now().Unix())
return iterable[rand.Intn(len(iterable))]
return iterable[random.Intn(len(iterable))]
}
11 changes: 8 additions & 3 deletions pkg/project/app_classic/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,14 @@ instance:
# OSGi components state tracking
component_stable:
skip: false
pids_ignored: []
pids_failed_activation: []
pids_unsatisfied_reference: []
pids:
include: []
exclude: []
match:
"disabled": []
"no config": []
"unsatisfied (reference)": []
"satisfied": []
# Sling Installer tracking
installer:
skip: false
Expand Down
11 changes: 8 additions & 3 deletions pkg/project/app_cloud/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,14 @@ instance:
# OSGi components state tracking
component_stable:
skip: false
pids_ignored: []
pids_failed_activation: []
pids_unsatisfied_reference: []
pids:
include: []
exclude: []
match:
"disabled": []
"no config": []
"unsatisfied (reference)": []
"satisfied": []
# Sling Installer tracking
installer:
skip: false
Expand Down
11 changes: 8 additions & 3 deletions pkg/project/instance/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,14 @@ instance:
# OSGi components state tracking
component_stable:
skip: false
pids_ignored: []
pids_failed_activation: []
pids_unsatisfied_reference: []
pids:
include: []
exclude: []
match:
"disabled": []
"no config": []
"unsatisfied (reference)": []
"satisfied": []
# Sling Installer tracking
installer:
skip: false
Expand Down

0 comments on commit 37cfa87

Please sign in to comment.