diff --git a/CHANGELOG.md b/CHANGELOG.md index 13eb48490..27f06fab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -628,3 +628,6 @@ Where the password is the value of the `þassword` key in `system/sec/relay-v3`. * Flush iptables rules created by om2. om3 now configures the firewall using nft only. +* Change `ips_per_node` to `mask_per_node`. The former was inadequate for large subnets (ipv6). For example, `ips_per_node=18446744073709551616` is easier expressed as `mask_per_node=64`. Backward compatibility is maintained for this release. + + diff --git a/core/driver/group.go b/core/driver/group.go index bd4a94f6d..d6ad13920 100644 --- a/core/driver/group.go +++ b/core/driver/group.go @@ -19,10 +19,6 @@ const ( GroupApp GroupSync GroupTask - GroupCertificate - GroupExpose - GroupRoute - GroupVhost GroupPool GroupNetwork GroupHeartbeat @@ -33,51 +29,43 @@ const ( ) var ( - resourceGroups = GroupIP | GroupVolume | GroupDisk | GroupFS | GroupShare | GroupContainer | GroupApp | GroupSync | GroupTask | GroupCertificate | GroupExpose | GroupRoute | GroupVhost + resourceGroups = GroupIP | GroupVolume | GroupDisk | GroupFS | GroupShare | GroupContainer | GroupApp | GroupSync | GroupTask toGroupID = map[string]Group{ - "ip": GroupIP, - "volume": GroupVolume, - "disk": GroupDisk, - "fs": GroupFS, - "share": GroupShare, - "container": GroupContainer, - "app": GroupApp, - "sync": GroupSync, - "task": GroupTask, - "certificate": GroupCertificate, - "expose": GroupExpose, - "route": GroupRoute, - "vhost": GroupVhost, - "pool": GroupPool, - "network": GroupNetwork, - "hb": GroupHeartbeat, - "array": GroupArray, - "switch": GroupSwitch, - "stonith": GroupStonith, - "backup": GroupBackup, + "ip": GroupIP, + "volume": GroupVolume, + "disk": GroupDisk, + "fs": GroupFS, + "share": GroupShare, + "container": GroupContainer, + "app": GroupApp, + "sync": GroupSync, + "task": GroupTask, + "pool": GroupPool, + "network": GroupNetwork, + "hb": GroupHeartbeat, + "array": GroupArray, + "switch": GroupSwitch, + "stonith": GroupStonith, + "backup": GroupBackup, } toGroupString = map[Group]string{ - GroupIP: "ip", - GroupVolume: "volume", - GroupDisk: "disk", - GroupFS: "fs", - GroupShare: "share", - GroupContainer: "container", - GroupApp: "app", - GroupSync: "sync", - GroupTask: "task", - GroupCertificate: "certificate", - GroupExpose: "expose", - GroupRoute: "route", - GroupVhost: "vhost", - GroupPool: "pool", - GroupNetwork: "network", - GroupHeartbeat: "hb", - GroupArray: "array", - GroupSwitch: "switch", - GroupStonith: "stonith", - GroupBackup: "backup", + GroupIP: "ip", + GroupVolume: "volume", + GroupDisk: "disk", + GroupFS: "fs", + GroupShare: "share", + GroupContainer: "container", + GroupApp: "app", + GroupSync: "sync", + GroupTask: "task", + GroupPool: "pool", + GroupNetwork: "network", + GroupHeartbeat: "hb", + GroupArray: "array", + GroupSwitch: "switch", + GroupStonith: "stonith", + GroupBackup: "backup", } ) diff --git a/core/instance/config.go b/core/instance/config.go index fb8201d84..013f09c50 100644 --- a/core/instance/config.go +++ b/core/instance/config.go @@ -63,8 +63,8 @@ type ( IsDisabled bool `json:"is_disabled"` IsMonitored bool `json:"is_monitored"` IsStandby bool `json:"is_standby"` - Restart int `json:"restart"` - RestartDelay *time.Duration `json:"restart_delay"` + Restart int `json:"restart,omitempty"` + RestartDelay *time.Duration `json:"restart_delay,omitempty"` } SubsetConfig struct { Parallel bool `json:"parallel,omitempty"` @@ -172,11 +172,13 @@ func (t Config) Unstructured() map[string]any { func (t ResourceConfig) Unstructured() map[string]any { m := map[string]any{ - "is_disabled": t.IsDisabled, - "is_monitored": t.IsMonitored, - "is_standby": t.IsStandby, - "restart": t.Restart, - "restart_delay": t.RestartDelay, + "is_disabled": t.IsDisabled, + "is_monitored": t.IsMonitored, + "is_standby": t.IsStandby, + "restart": t.Restart, + } + if t.RestartDelay != nil { + m["restart_delay"] = t.RestartDelay } return m } diff --git a/core/instance/instance_test.go b/core/instance/instance_test.go index 319444eb1..fe3f6fd42 100644 --- a/core/instance/instance_test.go +++ b/core/instance/instance_test.go @@ -71,7 +71,6 @@ func Test_Status_Unmarshal(t *testing.T) { Mtime: time.Date(2022, time.November, 28, 21, 46, 25, 849702075, time.UTC), State: provisioned.False, }, - Restart: 2, }, }, } diff --git a/core/instance/monitor.go b/core/instance/monitor.go index b3abf2458..e7682e476 100644 --- a/core/instance/monitor.go +++ b/core/instance/monitor.go @@ -10,7 +10,6 @@ import ( "github.com/google/uuid" "github.com/opensvc/om3/v3/core/status" - "github.com/opensvc/om3/v3/util/xmap" ) type ( @@ -72,11 +71,11 @@ type ( // ResourceMonitor describes the restart states maintained by the daemon // for an object instance. ResourceMonitor struct { - Restart ResourceMonitorRestart `json:"restart"` + Restart *ResourceMonitorRestart `json:"restart,omitempty"` } ResourceMonitorRestart struct { - Remaining int `json:"remaining"` - LastAt time.Time `json:"last_at"` + Remaining int `json:"remaining,omitempty"` + LastAt time.Time `json:"last_at,omitempty"` } MonitorState int @@ -200,12 +199,20 @@ func (t *MonitorGlobalExpect) UnmarshalText(b []byte) error { } } -func (rmon *ResourceMonitor) DecRestartRemaining() { - if rmon.Restart.Remaining > 0 { - rmon.Restart.Remaining -= 1 +func (m *ResourceMonitor) DecRestartRemaining() { + if m.Restart.Remaining > 0 { + m.Restart.Remaining -= 1 } } +func (t *ResourceMonitor) Unstructured() map[string]any { + m := map[string]any{} + if t.Restart != nil { + m["restart"] = t.Restart.Unstructured() + } + return m +} + func (m ResourceMonitors) Set(rid string, rmon ResourceMonitor) { m[rid] = rmon } @@ -219,7 +226,21 @@ func (m ResourceMonitors) Get(rid string) *ResourceMonitor { } func (m ResourceMonitors) DeepCopy() ResourceMonitors { - return xmap.Copy(m) + c := make(ResourceMonitors) + for k, v := range m { + c[k] = ResourceMonitor{ + Restart: v.Restart.DeepCopy(), + } + } + return c +} + +func (t ResourceMonitors) Unstructured() map[string]map[string]any { + m := make(map[string]map[string]any) + for k, v := range t { + m[k] = v.Unstructured() + } + return m } func (mon Monitor) DeepCopy() *Monitor { @@ -243,13 +264,17 @@ func (mon Monitor) DeepCopy() *Monitor { return &v } -func (t ResourceMonitor) Unstructured() map[string]any { - return map[string]any{ - "restart": t.Restart.Unstructured(), +func (t *ResourceMonitorRestart) DeepCopy() *ResourceMonitorRestart { + if t == nil { + return nil + } + return &ResourceMonitorRestart{ + Remaining: t.Remaining, + LastAt: t.LastAt, } } -func (t ResourceMonitorRestart) Unstructured() map[string]any { +func (t *ResourceMonitorRestart) Unstructured() map[string]any { return map[string]any{ "remaining": t.Remaining, "last_at": t.LastAt, @@ -286,14 +311,6 @@ func (t Monitor) Unstructured() map[string]any { return m } -func (t ResourceMonitors) Unstructured() map[string]map[string]any { - m := make(map[string]map[string]any) - for k, v := range t { - m[k] = v.Unstructured() - } - return m -} - func (t MonitorUpdate) String() string { s := fmt.Sprintf("CandidateOrchestrationID=%s", t.CandidateOrchestrationID) if t.State != nil { diff --git a/core/instance/monitor_test.go b/core/instance/monitor_test.go index ed045b752..d61d52168 100644 --- a/core/instance/monitor_test.go +++ b/core/instance/monitor_test.go @@ -36,7 +36,7 @@ func Test_Monitor_Unmarshal(t *testing.T) { StateUpdatedAt: t0, Resources: ResourceMonitors{ "fs#1": ResourceMonitor{ - Restart: ResourceMonitorRestart{ + Restart: &ResourceMonitorRestart{ Remaining: 1, LastAt: time.Date(2020, time.March, 4, 16, 33, 23, 167003830, time.UTC), }, @@ -62,8 +62,8 @@ func Test_Monitor_DeepCopy(t *testing.T) { LocalExpectUpdatedAt: time.Now(), GlobalExpectUpdatedAt: time.Now(), Resources: ResourceMonitors{ - "a": ResourceMonitor{Restart: ResourceMonitorRestart{Remaining: 1, LastAt: time.Now()}}, - "b": ResourceMonitor{Restart: ResourceMonitorRestart{Remaining: 8, LastAt: time.Now()}}, + "a": ResourceMonitor{Restart: &ResourceMonitorRestart{Remaining: 1, LastAt: time.Now()}}, + "b": ResourceMonitor{Restart: &ResourceMonitorRestart{Remaining: 8, LastAt: time.Now()}}, }, } mon2 := *mon1.DeepCopy() diff --git a/core/instance/states_render.go b/core/instance/states_render.go index 024e570a3..b32a73aa7 100644 --- a/core/instance/states_render.go +++ b/core/instance/states_render.go @@ -78,9 +78,11 @@ func (t States) LoadTreeNode(head *tree.Node) { subsetNode.AddColumn() subsetNode.AddColumn() parallel := "" - if subset, ok := t.Config.Subsets[resourceSetName]; ok { - if subset.Parallel { - parallel = "//" + if t.Config.ActorConfig != nil { + if subset, ok := t.Config.Subsets[resourceSetName]; ok { + if subset.Parallel { + parallel = "//" + } } } subsetNode.AddColumn().AddText(parallel) @@ -88,7 +90,7 @@ func (t States) LoadTreeNode(head *tree.Node) { lastSubset = r.Subset } doResource := func(n *tree.Node, r resource.Status) *tree.Column { - flags := ResourceFlagsString(r.ResourceID.Name, t.Monitor, t.Status, r) + flags := ResourceFlagsString(r.ResourceID.Name, t, r) n.AddColumn().AddText(r.ResourceID.Name) n.AddColumn().AddText(flags) n.AddColumn().AddText(colorstatus.Sprint(r.Status, rawconfig.Colorize)) diff --git a/core/instance/status.go b/core/instance/status.go index e2f6300b4..df19862b4 100644 --- a/core/instance/status.go +++ b/core/instance/status.go @@ -127,24 +127,34 @@ func (a ResourceOrder) Less(i, j int) bool { // P Provisioned // S Standby // Restart remaining, + More than 9 remaining, X UserStopped -func ResourceFlagsString(rid string, mon Monitor, status Status, rstatus resource.Status) string { +func ResourceFlagsString(rid string, states States, rstatus resource.Status) string { runningFlag := func() string { - if status.Running.Has(rid) { + if states.Status.Running.Has(rid) { return "R" } else { return "." } } restartFlag := func() string { + if states.Config.ActorConfig == nil { + // only actors have the Resources field + return "." + } retries := 0 - if rmon := mon.Resources.Get(rid); rmon != nil { - retries = rmon.Restart.Remaining + restart := 0 + if rcfg := states.Config.Resources.Get(rid); rcfg != nil { + restart = rcfg.Restart + } + if rmon := states.Monitor.Resources.Get(rid); rmon != nil { + if rmon.Restart != nil { + retries = rmon.Restart.Remaining + } } - s := rstatus.RestartFlag(retries) + s := rstatus.RestartFlag(restart, retries) if s == "." { return s } - if mon.LocalExpect != MonitorLocalExpectStarted || status.IsFrozen() { + if states.Monitor.LocalExpect != MonitorLocalExpectStarted || states.Status.IsFrozen() { s = rawconfig.Colorize.Secondary(s) } return s diff --git a/core/manifest/dbkeywords.go b/core/manifest/dbkeywords.go index 1c6c7cd8a..5ce1fb425 100644 --- a/core/manifest/dbkeywords.go +++ b/core/manifest/dbkeywords.go @@ -206,7 +206,7 @@ var ( } KWRestart = keywords.Keyword{ - Attr: "Restart", + Attr: "Restart.Count", Default: "0", Converter: "int", Option: "restart", @@ -215,7 +215,7 @@ var ( } KWRestartDelay = keywords.Keyword{ - Attr: "RestartDelay", + Attr: "Restart.Delay", Converter: "duration", Default: "500ms", Option: "restart_delay", diff --git a/core/object/actor.go b/core/object/actor.go index 2f6c3c567..58415ecf3 100644 --- a/core/object/actor.go +++ b/core/object/actor.go @@ -271,7 +271,7 @@ func (t *actor) ConfigureResources() { } driverGroup := rid.DriverGroup() if driverGroup == driver.GroupUnknown { - t.log.Attr("rid", k).Tracef("unknown driver group in rid %s", k) + t.log.Tracef("unknown driver group in rid %s", k) continue } typeKey := key.New(k, "type") @@ -306,30 +306,35 @@ func (t *actor) ConfigureResources() { } postponed[o.RID] = append(postponed[o.RID], r) default: - t.log.Attr("rid", k).Errorf("configure resource %s: %s", k, err) + r.SetConfigurationError(err) + t.log.Tracef("resource %s configuration error: %s", k, err) + t._resources = append(t._resources, r) } continue } dur := time.Now().Sub(rBegin) - t.log.Attr("rid", k).Attr("duration", dur).Tracef("resource %s configured in %s", k, dur) + t.log.Tracef("resource %s configured in %s", k, dur) t._resources = append(t._resources, r) } for _, resources := range postponed { for _, r := range resources { rBegin := time.Now() + k := r.RID() if err := t.ReconfigureResource(r); err != nil { - t.log.Attr("rid", r.RID()).Errorf("configure postponed resource %s: %s", r.RID(), err) + r.SetConfigurationError(err) + t.log.Tracef("postponed resource %s configuration error: %s", k, err) + t._resources = append(t._resources, r) continue } dur := time.Now().Sub(rBegin) - t.log.Attr("rid", r.RID()).Attr("duration", dur).Tracef("postponed resource %s configured in %s", r.RID(), dur) + t.log.Tracef("postponed resource %s configured in %s", k, dur) t._resources = append(t._resources, r) } } t.resources = t._resources t._resources = nil dur := time.Now().Sub(begin) - t.log.Attr("duration", dur).Tracef("all resources configured in %s", dur) + t.log.Tracef("%d resources configured in %s", len(t.resources), dur) return } @@ -339,6 +344,7 @@ func (t *actor) ReconfigureResource(r resource.Driver) error { func (t *actor) configureResource(r resource.Driver, rid string) error { r.SetRID(rid) + r.SetObject(t) m := r.Manifest() getDNS := func() ([]string, error) { n, err := t.Node() @@ -482,7 +488,6 @@ func (t *actor) configureResource(r resource.Driver, rid string) error { } } } - r.SetObject(t) r.SetPG(t.pgConfig(rid)) if i, ok := r.(resource.Configurer); ok { if err := i.Configure(); err != nil { diff --git a/core/object/actor_push_resinfo.go b/core/object/actor_push_resinfo.go index badc3ed49..e19e3ddcd 100644 --- a/core/object/actor_push_resinfo.go +++ b/core/object/actor_push_resinfo.go @@ -95,6 +95,9 @@ func (t *actor) masterResInfo(ctx context.Context) ([]resource.Info, error) { resourceLister := resourceselector.FromContext(ctx, t) barrier := actioncontext.To(ctx) err := t.ResourceSets().Do(ctx, resourceLister, barrier, "resinfo", func(ctx context.Context, r resource.Driver) error { + if r.GetConfigurationError() != nil { + return nil + } info, err := resource.GetInfo(ctx, r) if err != nil { return err diff --git a/core/object/actor_status.go b/core/object/actor_status.go index 1fe598d44..69e4249b1 100644 --- a/core/object/actor_status.go +++ b/core/object/actor_status.go @@ -226,6 +226,14 @@ func (t *actor) resourceStatusEval(ctx context.Context, data *instance.Status, m return nil } + if err := r.GetConfigurationError(); err != nil { + log := resource.NewStatusLog() + log.Error("%s", err) + resourceStatus.Log = log.Entries() + data.Resources[r.RID()] = resourceStatus + return nil + } + if monitoredOnly && !r.IsMonitored() { resourceStatus = data.Resources[r.RID()] sb.Post(r.RID(), resourceStatus.Status, false) diff --git a/core/object/core_action.go b/core/object/core_action.go index dbd624517..8b103c81f 100644 --- a/core/object/core_action.go +++ b/core/object/core_action.go @@ -306,6 +306,9 @@ func (t *actor) abortStartDrivers(ctx context.Context, resources resource.Driver q := make(chan bool, len(resources)) var wg sync.WaitGroup for _, r := range resources { + if r.GetConfigurationError() != nil { + return nil + } if v, err := t.isEncapNodeMatchingResource(r); err != nil { return err } else if !v { @@ -626,6 +629,10 @@ func (t *actor) action(ctx context.Context, fn resourceset.DoFunc) error { progressWrap := func(fn resourceset.DoFunc) resourceset.DoFunc { return func(ctx context.Context, r resource.Driver) error { + if err := r.GetConfigurationError(); err != nil { + r.Log().Warnf("skip resource with configuration error: %s", err) + return nil + } if v, err := t.isEncapNodeMatchingResource(r); err != nil { return err } else if !v { diff --git a/core/object/core_config.go b/core/object/core_config.go index 3faed22b1..549265134 100644 --- a/core/object/core_config.go +++ b/core/object/core_config.go @@ -84,7 +84,11 @@ func (t *core) Orchestrate() string { } func (t *core) FQDN() string { - return t.fqdn().String() + if fqdn := t.fqdn(); fqdn != nil { + return fqdn.String() + } else { + return "" + } } func (t *core) Domain() string { diff --git a/core/object/interfaces.go b/core/object/interfaces.go index d85d755c5..9935a6950 100644 --- a/core/object/interfaces.go +++ b/core/object/interfaces.go @@ -5,7 +5,6 @@ import ( "github.com/opensvc/om3/v3/core/keyop" "github.com/opensvc/om3/v3/core/rawconfig" - "github.com/opensvc/om3/v3/core/schedule" "github.com/opensvc/om3/v3/core/xconfig" "github.com/opensvc/om3/v3/util/key" ) @@ -31,8 +30,4 @@ type ( Update(context.Context, []string, []key.T, []keyop.T) error Unset(context.Context, ...key.T) error } - - scheduler interface { - Schedules() schedule.Table - } ) diff --git a/core/object/text/kw/node/pool.virtual.capabilities b/core/object/text/kw/node/pool.virtual.capabilities index 2d6b3bd94..3bb4fe4ee 100644 --- a/core/object/text/kw/node/pool.virtual.capabilities +++ b/core/object/text/kw/node/pool.virtual.capabilities @@ -2,9 +2,37 @@ The capabilities exposed by the virtual pool. Supported capabilities: -* `shared` +* `blk` + The pool can satisfy the `format=false` requirement. + +* `file` + The pool can satisfy the `format=true` requirement. + +* `move` + The pool volumes can host data for resources proposing live migration (e.g. container.kvm). + * `roo` + Read-Only from One node. + The pool can satisfy the `access=roo` requirement. + * `rox` + Read-Only from Many nodes. + The pool can satisfy the `access=rox` requirement. + * `rwo` + Read-Write from One node. + The pool can satisfy the `access=rwo` requirement. + * `rwx` -* `blk` + Read-Write from Many nodes. + The pool can satisfy the `access=rwx` requirement. + +* `shared` + The same technical object is used on all nodes. + +* `snap` + The volume can be snapshotted. + +* `volatile` + The pool can satisfy the `volatile=true` requirement. + diff --git a/core/omcmd/object_schedule_list.go b/core/omcmd/object_schedule_list.go index 84db6ab3c..4a4175667 100644 --- a/core/omcmd/object_schedule_list.go +++ b/core/omcmd/object_schedule_list.go @@ -51,9 +51,11 @@ func (t *CmdObjectScheduleList) extractLocal(selector string) (api.ScheduleList, if err != nil { return data, err } + var errs error for _, p := range paths { obj, err := object.New(p) if err != nil { + errs = errors.Join(errs, err) continue } i, ok := obj.(scheduler) @@ -84,7 +86,7 @@ func (t *CmdObjectScheduleList) extractLocal(selector string) (api.ScheduleList, data.Items = append(data.Items, item) } } - return data, nil + return data, errs } func (t *CmdObjectScheduleList) extractFromDaemons(selector string, c *client.T) (api.ScheduleList, error) { @@ -140,9 +142,6 @@ func (t *CmdObjectScheduleList) Run(kind string) error { return err } data, err := t.extract(mergedSelector, c) - if err != nil { - return err - } output.Renderer{ DefaultOutput: "tab=OBJECT:meta.object,NODE:meta.node,ACTION:data.action,KEY:data.key,LAST_RUN_AT:data.last_run_at,NEXT_RUN_AT:data.next_run_at,SCHEDULE:data.schedule", Output: t.Output, @@ -150,5 +149,5 @@ func (t *CmdObjectScheduleList) Run(kind string) error { Data: data, Colorize: rawconfig.Colorize, }.Print() - return nil + return err } diff --git a/core/pool/lookup.go b/core/pool/lookup.go index 93f398177..b19900f28 100644 --- a/core/pool/lookup.go +++ b/core/pool/lookup.go @@ -110,7 +110,7 @@ func (t Lookup) Do(ctx context.Context) (Pooler, error) { cause = append(cause, fmt.Sprintf("[%s] not volatile capable", p.Name())) continue } - if t.Volatile == false && HasCapability(p, CapVolatile) { + if t.Volatile == false && HasCapability(p, CapVolatile) && t.Type != "shm" { cause = append(cause, fmt.Sprintf("[%s] not persistent capable", p.Name())) continue } diff --git a/core/resource/info.go b/core/resource/info.go index f0cbad6a5..ef8bfae88 100644 --- a/core/resource/info.go +++ b/core/resource/info.go @@ -28,6 +28,10 @@ type ( infoer interface { Info(context.Context) (InfoKeys, error) } + + restarter interface { + GetRestart() Restart + } ) func GetInfo(ctx context.Context, r Driver) (Info, error) { @@ -62,16 +66,15 @@ func GetInfo(ctx context.Context, r Driver) (Info, error) { Key: "encap", Value: fmt.Sprint(r.IsEncap()), }, - { - Key: "restart", - Value: fmt.Sprint(r.RestartCount()), - }, - { - Key: "restart_delay", - Value: fmt.Sprint(r.GetRestartDelay()), - }, }, } + if i, ok := r.(restarter); ok { + restart := i.GetRestart() + info.Keys = append(info.Keys, + InfoKey{"restart_count", fmt.Sprint(restart.Count)}, + InfoKey{"restart_delay", fmt.Sprint(restart.Delay)}, + ) + } i, ok := r.(infoer) if !ok { return info, nil diff --git a/core/resource/resource.go b/core/resource/resource.go index 515909248..e25e28852 100644 --- a/core/resource/resource.go +++ b/core/resource/resource.go @@ -70,7 +70,6 @@ type ( GetObject() any GetPG() *pg.Config GetPGID() string - GetRestartDelay() time.Duration ID() *resourceid.T IsActionDisabled() bool IsDisabled() bool @@ -84,6 +83,9 @@ type ( IsStopped() bool IsStatusDisabled() bool + GetConfigurationError() error + SetConfigurationError(error) + // Label returns a formatted short description of the Resource Label(context.Context) string @@ -93,7 +95,6 @@ type ( MatchSubset(string) bool MatchTag(string) bool Requires(string) *resourcereqs.T - RestartCount() int RID() string RSubset() string SetObject(any) @@ -106,6 +107,14 @@ type ( VarDir() string } + Restart struct { + // Count is how many times imon should try to restart before giving up. + Count int + + // Delay is the duration between 2 restarts. + Delay *time.Duration + } + // T is the resource type, embedded in each drivers type T struct { Driver @@ -117,8 +126,6 @@ type ( Standby bool Shared bool Encap bool - Restart int - RestartDelay *time.Duration Tags *set.Set BlockingPreStart string BlockingPreStop string @@ -149,11 +156,12 @@ type ( EnableProvision bool EnableUnprovision bool - statusLog StatusLog - log plog.Logger - object any - objectDriver ObjectDriver - pg *pg.Config + configurationError error + statusLog StatusLog + log plog.Logger + object any + objectDriver ObjectDriver + pg *pg.Config } // devReservabler is an interface implemented by resource drivers that want the core resource @@ -214,9 +222,6 @@ type ( // collect site-wide about this resource. Info map[string]any `json:"info,omitempty"` - // Restart is the number of restart to be tried before giving up. - Restart int `json:"restart,omitempty"` - // Tags is a set of words attached to the resource. Tags TagSet `json:"tags,omitempty"` @@ -276,6 +281,14 @@ var ( ErrBarrier = errors.New("barrier hit") ) +func (t *Restart) GetRestart() Restart { + return *t +} + +func (t *Restart) SetRestart(n *Restart) { + t = n +} + // IsMonitoredFlag returns a one character representation of the IsMonitored state. func (t *Status) IsMonitoredFlag() string { if t.IsMonitored { @@ -293,11 +306,11 @@ func (t *Status) IsDisabledFlag() string { } // RestartFlag returns a one character representation of the Restart state. -func (t *Status) RestartFlag(retries int) string { +func (t *Status) RestartFlag(restart, retries int) string { switch { case t.IsStopped: return "X" - case t.Restart <= 0: + case restart <= 0: return "." case retries <= 0: return "0" @@ -363,7 +376,7 @@ func (t *T) IsOptional() bool { // IsEncap returns true if the resource definition contains encap=true. func (t *T) IsEncap() bool { - return t.Encap || t.Tags.Has("encap") + return t.Encap || t.MatchTag("encap") } // IsDisabled returns true if the resource definition contains disable=true. @@ -414,17 +427,12 @@ func (t *T) IsActionDisabled() bool { return t.MatchTag("noaction") } -// RestartCount returns the value of the Restart field -func (t *T) RestartCount() int { - return t.Restart +func (t *T) GetConfigurationError() error { + return t.configurationError } -// GetRestartDelay returns the duration between 2 restarts -func (t *T) GetRestartDelay() time.Duration { - if t.RestartDelay == nil { - return 500 * time.Millisecond - } - return *t.RestartDelay +func (t *T) SetConfigurationError(err error) { + t.configurationError = err } // RSubset returns the resource subset name @@ -591,6 +599,7 @@ func (t *T) trigger(ctx context.Context, s string) error { command.WithName(cmdArgs[0]), command.WithVarArgs(cmdArgs[1:]...), command.WithLogger(&t.log), + command.WithEnv(append(os.Environ(), "OPENSVC_RID="+t.RID())), command.WithStdoutLogLevel(zerolog.InfoLevel), command.WithStderrLogLevel(zerolog.ErrorLevel)) return cmd.Run() @@ -1120,6 +1129,10 @@ func stop(ctx context.Context, r Driver) error { func EvalStatus(ctx context.Context, r Driver) status.T { r.StatusLog().Reset() s := status.NotApplicable + if err := r.GetConfigurationError(); err != nil { + r.StatusLog().Error("%s", err) + return s + } var tags []string if r.IsActionDisabled() { tags = append(tags, "actions disabled") @@ -1237,7 +1250,6 @@ func GetStatus(ctx context.Context, r Driver) Status { IsStopped: r.IsStopped(), IsMonitored: r.IsMonitored(), - Restart: r.RestartCount(), IsOptional: r.IsOptional(), IsStandby: r.IsStandby(), IsDisabled: r.IsDisabled(), @@ -1384,7 +1396,6 @@ func (t *Status) Unstructured() map[string]any { "disable": t.IsDisabled, "optional": t.IsOptional, "encap": t.IsEncap, - "restart": t.Restart, "standby": t.IsStandby, "stopped": t.IsStopped, } diff --git a/core/resourceset/resourceset.go b/core/resourceset/resourceset.go index ec8202358..b6054add7 100644 --- a/core/resourceset/resourceset.go +++ b/core/resourceset/resourceset.go @@ -223,7 +223,7 @@ func (t T) doParallel(ctx context.Context, l ResourceLister, resources resource. } select { case <-ctx.Done(): - err = fmt.Errorf("timeout") + err = ctx.Err() case err = <-c: } q <- result{ @@ -292,6 +292,12 @@ func (t T) doSerial(ctx context.Context, l ResourceLister, resources resource.Dr hasHitBarrier := false selectedResources := l.Resources() for _, r := range resources { + select { + case <-ctx.Done(): + return hasHitBarrier, ctx.Err() + default: + // pass + } if hasHitBarrier { break } @@ -305,29 +311,22 @@ func (t T) doSerial(ctx context.Context, l ResourceLister, resources resource.Dr if pgMgr != nil { pgMgr.Register(r.GetPG()) } - var err error - c := make(chan error, 1) - if err = l.ReconfigureResource(r); err == nil { - c <- fn(ctx, r) + if err := l.ReconfigureResource(r); err != nil { + r.SetConfigurationError(err) } - select { - case <-ctx.Done(): - err = fmt.Errorf("timeout") - case err = <-c: - } - switch { - case err == nil: + err := fn(ctx, r) + if err == nil { continue - case errors.Is(err, resource.ErrBarrier): + } + if errors.Is(err, resource.ErrBarrier) { // linkWrap executed resourceset.L.Do again with a fn that can return ErrBarrier return true, nil - case r.IsOptional(): + } + if r.IsOptional() { r.Log().Warnf("error from optional resource: %s", err) - continue - default: - r.Log().Errorf("%s", err) - return hasHitBarrier, fmt.Errorf("%s: %w", rid, err) } + r.Log().Errorf("%s", err) + return hasHitBarrier, fmt.Errorf("%s: %w", rid, err) } return hasHitBarrier, nil } diff --git a/core/tui/instance.go b/core/tui/instance.go index 8893499f9..411763c68 100644 --- a/core/tui/instance.go +++ b/core/tui/instance.go @@ -249,7 +249,7 @@ func (t *App) updateInstanceView() { return tview.NewTableCell(s).SetSelectable(false) } cellFlags := func(rid string, resourceStatus resource.Status, instanceState instance.States) *tview.TableCell { - s := instance.ResourceFlagsString(rid, instanceState.Monitor, instanceState.Status, resourceStatus) + s := instance.ResourceFlagsString(rid, instanceState, resourceStatus) s = tview.TranslateANSI(s) return tview.NewTableCell(s).SetSelectable(false) } diff --git a/daemon/api/api.yaml b/daemon/api/api.yaml index 9783e6847..0e8e6ad19 100644 --- a/daemon/api/api.yaml +++ b/daemon/api/api.yaml @@ -7066,7 +7066,6 @@ components: - is_monitored - is_standby - restart - - restart_delay properties: is_disabled: type: boolean @@ -7208,8 +7207,6 @@ components: x-go-type-import: path: github.com/opensvc/om3/v3/core/instance type: object - required: - - restart properties: restart: $ref: '#/components/schemas/ResourceMonitorRestart' @@ -7253,7 +7250,6 @@ components: - monitor - optional - provisioned - - restart - standby - status - subset @@ -7291,8 +7287,6 @@ components: Errors in optional resource don't stop a state transition action provisioned: $ref: '#/components/schemas/ResourceProvisionStatus' - restart: - type: integer standby: type: boolean description: | diff --git a/daemon/api/codegen_client_gen.go b/daemon/api/codegen_client_gen.go index 197a5ac3c..55bdb943e 100644 --- a/daemon/api/codegen_client_gen.go +++ b/daemon/api/codegen_client_gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package api import ( diff --git a/daemon/api/codegen_server_gen.go b/daemon/api/codegen_server_gen.go index a84d60f46..4cab0c0ff 100644 --- a/daemon/api/codegen_server_gen.go +++ b/daemon/api/codegen_server_gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package api import ( @@ -6230,281 +6230,281 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/api/codegen_type_gen.go b/daemon/api/codegen_type_gen.go index b4fd94ae6..d3b968601 100644 --- a/daemon/api/codegen_type_gen.go +++ b/daemon/api/codegen_type_gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. package api import ( diff --git a/daemon/imon/main_cmd.go b/daemon/imon/main_cmd.go index 2827b0636..80525aceb 100644 --- a/daemon/imon/main_cmd.go +++ b/daemon/imon/main_cmd.go @@ -1145,10 +1145,12 @@ func (t *Manager) initResourceMonitor() { m := make(instance.ResourceMonitors, 0) for rid, rcfg := range t.instConfig.Resources { - m[rid] = instance.ResourceMonitor{ - Restart: instance.ResourceMonitorRestart{ + resourceMonitor := instance.ResourceMonitor{} + if rcfg.Restart > 0 { + resourceMonitor.Restart = &instance.ResourceMonitorRestart{ Remaining: rcfg.Restart, - }, + } + m[rid] = resourceMonitor } if rcfg.IsMonitored && hasMonitorActionNone { t.orchestrationResource(rcfg.IsStandby).log.Infof("rid %s is monitored, but monitor action is none", rid) diff --git a/daemon/imon/orchestration_resource_restart.go b/daemon/imon/orchestration_resource_restart.go index 5ebd88d6b..82910261a 100644 --- a/daemon/imon/orchestration_resource_restart.go +++ b/daemon/imon/orchestration_resource_restart.go @@ -268,9 +268,6 @@ func (t *Manager) orchestrateResourceRestart() { continue } rmon := t.state.Resources.Get(rid) - if rmon == nil { - continue - } needRestart, needMonitorAction, err := t.orchestrateResourcePlan(rid, rcfg, rmon, rstat, started) if err != nil { t.log.Errorf("orchestrate resource plan for resource %s: %s", rid, err) @@ -476,9 +473,6 @@ func (t *Manager) orchestrateResourcePlan(rid string, rcfg *instance.ResourceCon if rcfg == nil { err = fmt.Errorf("orchestrate resource plan called with nil resource monitor") return - } else if rmon == nil { - err = fmt.Errorf("orchestrate resource plan called with nil resource config") - return } or := t.orchestrationResource(rcfg.IsStandby) @@ -490,6 +484,9 @@ func (t *Manager) orchestrateResourcePlan(rid string, rcfg *instance.ResourceCon } resetRemaining := func(rid string, reason string) { + if rmon == nil || rmon.Restart == nil { + return + } if rmon.Restart.Remaining != rcfg.Restart { or.log.Infof("rid %s %s: reset restart count to config value (%d -> %d)", rid, reason, rmon.Restart.Remaining, rcfg.Restart) rmon.Restart.Remaining = rcfg.Restart @@ -521,7 +518,12 @@ func (t *Manager) orchestrateResourcePlan(rid string, rcfg *instance.ResourceCon case t.monitorActionCalled(): or.log.Tracef("planFor rid %s skipped: monitor action has been already called", rid) case rcfg.IsStandby || started: - if rmon.Restart.Remaining == 0 && rcfg.IsMonitored { + if rmon == nil || rmon.Restart == nil { + if rcfg.IsMonitored { + or.log.Infof("rid %s status %s, no restart configured: need monitor action", rid, rStatus.Status) + needMonitorAction = true + } + } else if rmon.Restart.Remaining == 0 && rcfg.IsMonitored { or.log.Infof("rid %s status %s, restart remaining %d out of %d: need monitor action", rid, rStatus.Status, rmon.Restart.Remaining, rcfg.Restart) needMonitorAction = true } else if rmon.Restart.Remaining > 0 { diff --git a/drivers/resapp/base.go b/drivers/resapp/base.go index 2e24bbedd..933252170 100644 --- a/drivers/resapp/base.go +++ b/drivers/resapp/base.go @@ -16,6 +16,7 @@ import ( // BaseT is the app base driver structure type BaseT struct { resource.T + resource.Restart RetCodes string `json:"retcodes"` Path naming.Path `json:"path"` Nodes []string `json:"nodes"` diff --git a/drivers/rescontainerkvm/main.go b/drivers/rescontainerkvm/main.go index 85869aaaf..fd9ba733e 100644 --- a/drivers/rescontainerkvm/main.go +++ b/drivers/rescontainerkvm/main.go @@ -53,6 +53,7 @@ const ( type ( T struct { resource.T + resource.Restart resource.SSH resource.SCSIPersistentReservation Path naming.Path `json:"path"` diff --git a/drivers/rescontainerlxc/main.go b/drivers/rescontainerlxc/main.go index 59ee2d6b0..cc70c8b15 100644 --- a/drivers/rescontainerlxc/main.go +++ b/drivers/rescontainerlxc/main.go @@ -55,6 +55,7 @@ var _ resource.Encaper = (*T)(nil) type ( T struct { resource.T + resource.Restart resource.SSH resource.SCSIPersistentReservation Path naming.Path `json:"path"` diff --git a/drivers/rescontainerocibase/main.go b/drivers/rescontainerocibase/main.go index a92116f57..79239b109 100644 --- a/drivers/rescontainerocibase/main.go +++ b/drivers/rescontainerocibase/main.go @@ -46,6 +46,7 @@ import ( type ( BT struct { resource.T + resource.Restart resource.SCSIPersistentReservation ObjectDomain string `json:"object_domain"` PG pg.Config `json:"pg"` diff --git a/drivers/rescontainervbox/main.go b/drivers/rescontainervbox/main.go index 97aeae0e7..8265a96b5 100644 --- a/drivers/rescontainervbox/main.go +++ b/drivers/rescontainervbox/main.go @@ -40,6 +40,7 @@ import ( type ( T struct { resource.T + resource.Restart resource.SSH resource.SCSIPersistentReservation Path naming.Path `json:"path"` diff --git a/drivers/resdisk/main.go b/drivers/resdisk/main.go index 260e88304..ee057590a 100644 --- a/drivers/resdisk/main.go +++ b/drivers/resdisk/main.go @@ -11,6 +11,7 @@ import ( type ( T struct { resource.T + resource.Restart resource.SCSIPersistentReservation PromoteRW bool } diff --git a/drivers/resfsdir/main.go b/drivers/resfsdir/main.go index 5788a2e22..db35b1e66 100644 --- a/drivers/resfsdir/main.go +++ b/drivers/resfsdir/main.go @@ -21,6 +21,7 @@ const ( type ( T struct { resource.T + resource.Restart Path string `json:"path"` User *user.User `json:"user"` Group *user.Group `json:"group"` diff --git a/drivers/resfsflag/main.go b/drivers/resfsflag/main.go index 256b38d96..9d5c86cd3 100644 --- a/drivers/resfsflag/main.go +++ b/drivers/resfsflag/main.go @@ -22,6 +22,7 @@ import ( // T is the driver structure. type T struct { resource.T + resource.Restart resource.SSH Path naming.Path `json:"path"` Nodes []string `json:"nodes"` diff --git a/drivers/resfshost/main.go b/drivers/resfshost/main.go index 7b8a17182..787436b0f 100644 --- a/drivers/resfshost/main.go +++ b/drivers/resfshost/main.go @@ -31,6 +31,7 @@ import ( type ( T struct { resource.T + resource.Restart resource.SCSIPersistentReservation Path naming.Path MountPoint string `json:"mnt"` diff --git a/drivers/resfszfs/main.go b/drivers/resfszfs/main.go index 1cfeb8d7f..8a4e7b66b 100644 --- a/drivers/resfszfs/main.go +++ b/drivers/resfszfs/main.go @@ -30,6 +30,7 @@ import ( type ( T struct { resource.T + resource.Restart MountPoint string `json:"mnt"` Device string `json:"dev"` MountOptions string `json:"mnt_opt"` diff --git a/drivers/resipcni/main.go b/drivers/resipcni/main.go index 8766b3a6c..50e120997 100644 --- a/drivers/resipcni/main.go +++ b/drivers/resipcni/main.go @@ -36,6 +36,7 @@ import ( type ( T struct { resource.T + resource.Restart Path naming.Path DNS []string diff --git a/drivers/resiphost/main.go b/drivers/resiphost/main.go index 36266b717..d3c4da8c6 100644 --- a/drivers/resiphost/main.go +++ b/drivers/resiphost/main.go @@ -30,6 +30,7 @@ const ( type ( T struct { resource.T + resource.Restart Path naming.Path ObjectFQDN string diff --git a/drivers/resipnetns/main.go b/drivers/resipnetns/main.go index c1e10eb14..b5e62a5d4 100644 --- a/drivers/resipnetns/main.go +++ b/drivers/resipnetns/main.go @@ -38,6 +38,7 @@ const ( type ( T struct { resource.T + resource.Restart Path naming.Path ObjectFQDN string diff --git a/drivers/resiproute/main.go b/drivers/resiproute/main.go index ceaa6226b..aac2544ce 100644 --- a/drivers/resiproute/main.go +++ b/drivers/resiproute/main.go @@ -14,6 +14,7 @@ type T struct { NetNS string `json:"netns"` Dev string `json:"dev"` resource.T + resource.Restart } // New allocates a new driver diff --git a/drivers/ressharenfs/main.go b/drivers/ressharenfs/main.go index 2c0d92c45..55e94ae65 100644 --- a/drivers/ressharenfs/main.go +++ b/drivers/ressharenfs/main.go @@ -14,6 +14,7 @@ import ( // T is the driver structure. type T struct { resource.T + resource.Restart SharePath string `json:"path"` ShareOpts string `json:"opts"` diff --git a/drivers/ressyncsymsrdfs/main.go b/drivers/ressyncsymsrdfs/main.go index af03f7667..7eacf6381 100644 --- a/drivers/ressyncsymsrdfs/main.go +++ b/drivers/ressyncsymsrdfs/main.go @@ -33,6 +33,7 @@ import ( type ( T struct { ressync.T + resource.Restart SymDG string SymID string RDFG int diff --git a/drivers/resvol/main.go b/drivers/resvol/main.go index b29a6ecbd..2a3f66963 100644 --- a/drivers/resvol/main.go +++ b/drivers/resvol/main.go @@ -52,6 +52,7 @@ import ( type ( T struct { resource.T + resource.Restart datarecv.DataRecv Name string `json:"name"` Access string `json:"access"`