Skip to content

Commit

Permalink
Merge pull request #216 from wttech/osgi-components-checking
Browse files Browse the repository at this point in the history
OSGi components checking
  • Loading branch information
krystian-panek-vmltech authored Nov 23, 2023
2 parents 4db746f + d814e50 commit d6526c9
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 36 deletions.
5 changes: 5 additions & 0 deletions examples/docker/src/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ instance:
- "org.osgi.service.component.runtime.ServiceComponentRuntime"
- "java.util.ResourceBundle"
received_max_age: 5s
# OSGi components state tracking
component_stable:
pids_ignored: []
pids_failed_activation: ["*"]
pids_unsatisfied_reference: []
# Sling Installer tracking
installer:
# JMX state checking
Expand Down
12 changes: 12 additions & 0 deletions pkg/cfg/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,29 @@ func (c *Config) setDefaults() {
v.SetDefault("instance.check.await_started.timeout", time.Minute*30)
v.SetDefault("instance.check.await_stopped.timeout", time.Minute*10)

v.SetDefault("instance.check.reachable.skip", false)
v.SetDefault("instance.check.reachable.timeout", time.Second*3)

v.SetDefault("instance.check.bundle_stable.skip", false)
v.SetDefault("instance.check.bundle_stable.symbolic_names_ignored", []string{})

v.SetDefault("instance.check.event_stable.skip", false)
v.SetDefault("instance.check.event_stable.received_max_age", time.Second*5)
v.SetDefault("instance.check.event_stable.topics_unstable", []string{"org/osgi/framework/ServiceEvent/*", "org/osgi/framework/FrameworkEvent/*", "org/osgi/framework/BundleEvent/*"})
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.installer.skip", false)
v.SetDefault("instance.check.installer.state", true)
v.SetDefault("instance.check.installer.pause", true)

v.SetDefault("instance.check.path_ready.timeout", time.Second*10)

v.SetDefault("instance.check.login_page.skip", false)
v.SetDefault("instance.check.login_page.path", "/libs/granite/core/content/login.html")
v.SetDefault("instance.check.login_page.status_code", 200)
v.SetDefault("instance.check.login_page.contained_text", "QUICKSTART_HOMEPAGE")
Expand Down
120 changes: 97 additions & 23 deletions pkg/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Checker interface {
}

type CheckSpec struct {
Skip bool // occasionally skip checking e.g. due to performance reasons
Mandatory bool // indicates if next checks should be skipped if that particular one fails
}

Expand Down Expand Up @@ -65,37 +66,29 @@ func (c AwaitChecker) Check(ctx CheckContext, _ Instance) CheckResult {
}

func (c AwaitChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: true}
return CheckSpec{Skip: false, Mandatory: true}
}

type AwaitChecker struct {
Timeout time.Duration
ExpectedState string
}

func NewEventStableChecker(opts *CheckOpts) EventStableChecker {
cv := opts.manager.aem.config.Values()

return EventStableChecker{
ReceivedMaxAge: cv.GetDuration("instance.check.event_stable.received_max_age"),
TopicsUnstable: cv.GetStringSlice("instance.check.event_stable.topics_unstable"),
DetailsIgnored: cv.GetStringSlice("instance.check.event_stable.details_ignored"),
}
}

func NewBundleStableChecker(opts *CheckOpts) BundleStableChecker {
cv := opts.manager.aem.config.Values()

return BundleStableChecker{
Skip: cv.GetBool("instance.check.bundle_stable.skip"),
SymbolicNamesIgnored: cv.GetStringSlice("instance.check.bundle_stable.symbolic_names_ignored"),
}
}

func (c BundleStableChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: true}
return CheckSpec{Skip: c.Skip, Mandatory: true}
}

type BundleStableChecker struct {
Skip bool
SymbolicNamesIgnored []string
}

Expand Down Expand Up @@ -131,13 +124,25 @@ func (c BundleStableChecker) Check(_ CheckContext, instance Instance) CheckResul
}

type EventStableChecker struct {
Skip bool
ReceivedMaxAge time.Duration
TopicsUnstable []string
DetailsIgnored []string
}

func NewEventStableChecker(opts *CheckOpts) EventStableChecker {
cv := opts.manager.aem.config.Values()

return EventStableChecker{
Skip: cv.GetBool("instance.check.event_stable.skip"),
ReceivedMaxAge: cv.GetDuration("instance.check.event_stable.received_max_age"),
TopicsUnstable: cv.GetStringSlice("instance.check.event_stable.topics_unstable"),
DetailsIgnored: cv.GetStringSlice("instance.check.event_stable.details_ignored"),
}
}

func (c EventStableChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: true}
return CheckSpec{Skip: c.Skip, Mandatory: true}
}

func (c EventStableChecker) Check(_ CheckContext, instance Instance) CheckResult {
Expand Down Expand Up @@ -180,22 +185,86 @@ func (c EventStableChecker) Check(_ CheckContext, instance Instance) CheckResult
}
}

func NewInstallerChecker(opts *CheckOpts) InstallerChecker {
type ComponentStableChecker struct {
Skip bool
PIDsIgnored []string
PIDsFailedActivation []string
PIDsUnsatisfiedReference []string
}

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

return InstallerChecker{
State: cv.GetBool("instance.check.installer.state"),
Pause: cv.GetBool("instance.check.installer.pause"),
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"),
}
}

func (c ComponentStableChecker) Spec() CheckSpec {
return CheckSpec{Skip: c.Skip, Mandatory: true}
}

func (c ComponentStableChecker) Check(_ CheckContext, instance Instance) CheckResult {
components, err := instance.osgi.componentManager.List()
if err != nil {
return CheckResult{
ok: false,
message: "components unknown",
err: err,
}
}

failedComponents := lo.Filter(components.List, func(component osgi.ComponentListItem, _ int) bool {
return !stringsx.MatchSome(component.PID, c.PIDsIgnored) && stringsx.MatchSome(component.PID, c.PIDsFailedActivation) && component.State == osgi.ComponentStateFailedActivation
})
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,
}
}

unsatisfiedComponents := lo.Filter(components.List, func(component osgi.ComponentListItem, _ int) bool {
return !stringsx.MatchSome(component.PID, c.PIDsIgnored) && stringsx.MatchSome(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,
}
}

return CheckResult{
ok: true,
message: "all components stable",
}
}

type InstallerChecker struct {
Skip bool
State bool
Pause bool
}

func NewInstallerChecker(opts *CheckOpts) InstallerChecker {
cv := opts.manager.aem.config.Values()

return InstallerChecker{
Skip: cv.GetBool("instance.check.installer.skip"),
State: cv.GetBool("instance.check.installer.state"),
Pause: cv.GetBool("instance.check.installer.pause"),
}
}

func (c InstallerChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: false}
return CheckSpec{Skip: c.Skip, Mandatory: false}
}

func (c InstallerChecker) Check(_ CheckContext, instance Instance) CheckResult {
Expand Down Expand Up @@ -247,7 +316,7 @@ func NewStatusStoppedChecker() StatusStoppedChecker {
type StatusStoppedChecker struct{}

func (c StatusStoppedChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: true}
return CheckSpec{Skip: false, Mandatory: true}
}

func (c StatusStoppedChecker) Check(_ CheckContext, instance Instance) CheckResult {
Expand Down Expand Up @@ -285,20 +354,22 @@ func NewReachableChecker(opts *CheckOpts, reachable bool) ReachableHTTPChecker {
cv := opts.manager.aem.config.Values()

return ReachableHTTPChecker{
Skip: cv.GetBool("instance.check.reachable.skip"),
Mandatory: reachable,
Reachable: reachable,
Timeout: cv.GetDuration("instance.check.reachable.timeout"),
}
}

type ReachableHTTPChecker struct {
Skip bool
Mandatory bool
Reachable bool
Timeout time.Duration
}

func (c ReachableHTTPChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: c.Mandatory}
return CheckSpec{Skip: c.Skip, Mandatory: c.Mandatory}
}

func (c ReachableHTTPChecker) Check(_ CheckContext, instance Instance) CheckResult {
Expand All @@ -321,17 +392,19 @@ func (c ReachableHTTPChecker) Check(_ CheckContext, instance Instance) CheckResu

func NewLoginPageChecker(opts *CheckOpts) PathHTTPChecker {
cv := opts.manager.aem.config.Values()
return NewPathReadyChecker(opts, "login page",
return NewPathReadyChecker(opts, cv.GetBool("instance.check.login_page.skip"),
"login page",
cv.GetString("instance.check.login_page.path"),
cv.GetInt("instance.check.login_page.status_code"),
cv.GetString("instance.check.login_page.contained_text"),
)
}

func NewPathReadyChecker(opts *CheckOpts, name string, path string, statusCode int, containedText string) PathHTTPChecker {
func NewPathReadyChecker(opts *CheckOpts, skip bool, name string, path string, statusCode int, containedText string) PathHTTPChecker {
cv := opts.manager.aem.config.Values()

return PathHTTPChecker{
Skip: skip,
Name: name,
Path: path,
RequestTimeout: cv.GetDuration("instance.check.path_ready.timeout"),
Expand All @@ -341,10 +414,11 @@ func NewPathReadyChecker(opts *CheckOpts, name string, path string, statusCode i
}

func (c PathHTTPChecker) Spec() CheckSpec {
return CheckSpec{Mandatory: false}
return CheckSpec{Skip: c.Skip, Mandatory: false}
}

type PathHTTPChecker struct {
Skip bool
Name string
Path string
RequestTimeout time.Duration
Expand Down
24 changes: 15 additions & 9 deletions pkg/instance_manager_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ type CheckOpts struct {
AwaitStrict bool
Skip bool

Reachable ReachableHTTPChecker
BundleStable BundleStableChecker
EventStable EventStableChecker
Installer InstallerChecker
AwaitStarted AwaitChecker
Unreachable ReachableHTTPChecker
StatusStopped StatusStoppedChecker
AwaitStopped AwaitChecker
LoginPage PathHTTPChecker
Reachable ReachableHTTPChecker
BundleStable BundleStableChecker
EventStable EventStableChecker
ComponentStable ComponentStableChecker
Installer InstallerChecker
AwaitStarted AwaitChecker
Unreachable ReachableHTTPChecker
StatusStopped StatusStoppedChecker
AwaitStopped AwaitChecker
LoginPage PathHTTPChecker
}

func NewCheckOpts(manager *InstanceManager) *CheckOpts {
Expand All @@ -43,6 +44,7 @@ func NewCheckOpts(manager *InstanceManager) *CheckOpts {
result.Reachable = NewReachableChecker(result, true)
result.BundleStable = NewBundleStableChecker(result)
result.EventStable = NewEventStableChecker(result)
result.ComponentStable = NewComponentStableChecker(result)
result.AwaitStarted = NewAwaitChecker(result, "started")
result.Installer = NewInstallerChecker(result)
result.StatusStopped = NewStatusStoppedChecker()
Expand Down Expand Up @@ -129,6 +131,9 @@ func (im *InstanceManager) CheckOne(i Instance, checks []Checker) ([]CheckResult
func (im *InstanceManager) checkOne(ctx context.Context, i Instance, checks []Checker) ([]CheckResult, error) {
var results []CheckResult
for _, check := range checks {
if check.Spec().Skip {
continue
}
result := check.Check(ctx.Value(checkContextKey{}).(CheckContext), i)
results = append(results, result)
if result.abort {
Expand Down Expand Up @@ -174,6 +179,7 @@ func (im *InstanceManager) AwaitStarted(instances []Instance) error {
im.CheckOpts.EventStable,
im.CheckOpts.Installer,
im.CheckOpts.LoginPage,
im.CheckOpts.ComponentStable,
}
}
return im.CheckUntilDone(instances, im.CheckOpts, checkers)
Expand Down
10 changes: 6 additions & 4 deletions pkg/osgi/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ const (
)

const (
ComponentStateActive = "active"
ComponentStateSatisfied = "satisfied"
ComponentStateNoConfig = "no config"
ComponentStateDisabled = "disabled"
ComponentStateActive = "active"
ComponentStateSatisfied = "satisfied"
ComponentStateUnsatisfiedReference = "unsatisfied (reference)"
ComponentStateNoConfig = "no config"
ComponentStateDisabled = "disabled"
ComponentStateFailedActivation = "failed activation"
)
5 changes: 5 additions & 0 deletions pkg/project/app_classic/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ instance:
- "org.osgi.service.component.runtime.ServiceComponentRuntime"
- "java.util.ResourceBundle"
received_max_age: 5s
# OSGi components state tracking
component_stable:
pids_ignored: []
pids_failed_activation: ["*"]
pids_unsatisfied_reference: []
# Sling Installer tracking
installer:
# JMX state checking
Expand Down
5 changes: 5 additions & 0 deletions pkg/project/app_cloud/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ instance:
- "org.osgi.service.component.runtime.ServiceComponentRuntime"
- "java.util.ResourceBundle"
received_max_age: 5s
# OSGi components state tracking
component_stable:
pids_ignored: []
pids_failed_activation: ["*"]
pids_unsatisfied_reference: []
# Sling Installer tracking
installer:
# JMX state checking
Expand Down
5 changes: 5 additions & 0 deletions pkg/project/instance/aem/default/etc/aem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ instance:
- "org.osgi.service.component.runtime.ServiceComponentRuntime"
- "java.util.ResourceBundle"
received_max_age: 5s
# OSGi components state tracking
component_stable:
pids_ignored: []
pids_failed_activation: ["*"]
pids_unsatisfied_reference: []
# Sling Installer tracking
installer:
# JMX state checking
Expand Down

0 comments on commit d6526c9

Please sign in to comment.