Skip to content

Commit 382f495

Browse files
tas50claude
andauthored
✨ Add static field to service resource (#3288) (#6736)
Add a `static` boolean field to the service resource that indicates whether a systemd unit file has no [Install] section and cannot be enabled or disabled. This allows users to distinguish between services that are disabled vs those that are static. Supported in both the command-based systemd manager (parses `systemctl list-unit-files` STATE column) and the filesystem-based manager (detects absence of [Install] section in unit files). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d748ba8 commit 382f495

7 files changed

Lines changed: 38 additions & 0 deletions

File tree

providers/os/resources/os.lr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,8 @@ service @defaults("name running enabled type") {
863863
type string
864864
// Whether the service is masked
865865
masked bool
866+
// Whether the service is static (unit file has no [Install] section and cannot be enabled/disabled)
867+
static bool
866868
}
867869

868870
// Services configured on this system

providers/os/resources/os.lr.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

providers/os/resources/os.lr.versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ service.installed 9.0.0
796796
service.masked 9.0.0
797797
service.name 9.0.0
798798
service.running 9.0.0
799+
service.static 11.8.12
799800
service.type 9.0.0
800801
services 9.0.0
801802
services.list 9.0.0

providers/os/resources/services.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func initService(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[str
5454
res.Type.State = plugin.StateIsSet | plugin.StateIsNull
5555
res.Enabled = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
5656
res.Masked = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
57+
res.Static = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
5758
return nil, res, nil
5859
}
5960

@@ -102,6 +103,7 @@ func (x *mqlServices) list() ([]any, error) {
102103
"masked": llx.BoolData(srv.Masked),
103104
"running": llx.BoolData(srv.Running),
104105
"type": llx.StringData(srv.Type),
106+
"static": llx.BoolData(srv.Static),
105107
})
106108
if err != nil {
107109
return nil, err

providers/os/resources/services/manager.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Service struct {
2020
Running bool
2121
Enabled bool
2222
Masked bool
23+
Static bool
2324
Path string
2425
}
2526

providers/os/resources/services/systemd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func ParseServiceSystemDUnitFiles(input io.Reader) ([]*Service, error) {
6969
Name: name,
7070
Enabled: fields[1] == "enabled",
7171
Masked: fields[1] == "masked",
72+
Static: fields[1] == "static",
7273
Type: "systemd",
7374
}
7475

@@ -173,6 +174,8 @@ type unitInfo struct {
173174
// isDep is true of this unit is found in the dependency tree starting
174175
// from the default.target
175176
isDep bool
177+
// hasInstall is true if the unit file has an [Install] section
178+
hasInstall bool
176179
// service is only set for socket units. It contains an optional name.target.
177180
// If not provided, socketname.service is activated for the socket
178181
service string
@@ -221,6 +224,7 @@ func (s *SystemdFSServiceManager) List() ([]*Service, error) {
221224
Installed: !v.missing,
222225
Enabled: !v.missing && v.isDep,
223226
Masked: v.masked,
227+
Static: !v.missing && !v.masked && !v.hasInstall,
224228
})
225229
}
226230
return services, nil
@@ -415,6 +419,8 @@ func (s *SystemdFSServiceManager) readUnit(unitPath string, uInfo *unitInfo) err
415419
}
416420
} else if o.Section == "Socket" && o.Name == "Service" {
417421
uInfo.service = o.Value
422+
} else if o.Section == "Install" {
423+
uInfo.hasInstall = true
418424
}
419425
}
420426

providers/os/resources/services/systemd_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ func TestParseServiceSystemDUnitFiles(t *testing.T) {
7575
// check for masked element
7676
assert.Equal(t, "cryptdisks", m[30].Name, "service name detected")
7777
assert.Equal(t, true, m[30].Masked, "service is masked")
78+
assert.Equal(t, false, m[30].Static, "masked service is not static")
79+
80+
// check for static element (alsa-restore is the third service, index 2)
81+
assert.Equal(t, "alsa-restore", m[2].Name, "service name detected")
82+
assert.Equal(t, true, m[2].Static, "service is static")
83+
assert.Equal(t, false, m[2].Enabled, "static service is not enabled")
84+
assert.Equal(t, false, m[2].Masked, "static service is not masked")
85+
86+
// check that enabled service is not static
87+
assert.Equal(t, "accounts-daemon", m[0].Name, "service name detected")
88+
assert.Equal(t, false, m[0].Static, "enabled service is not static")
7889
}
7990

8091
func TestParseServiceSystemDUnitFilesPhoton(t *testing.T) {
@@ -133,6 +144,7 @@ func TestSystemdFS(t *testing.T) {
133144
State: ServiceUnknown,
134145
Installed: true,
135146
Enabled: true,
147+
Static: true,
136148
}, servicesMap["aliased"])
137149
assert.Contains(t, servicesMap, "aliased-wants")
138150
assert.Contains(t, servicesMap, "aliased-requires")
@@ -163,6 +175,7 @@ func TestSystemdFS(t *testing.T) {
163175
State: ServiceUnknown,
164176
Installed: true,
165177
Enabled: true,
178+
Static: true,
166179
}, servicesMap["implicit-socket"])
167180
assert.Contains(t, servicesMap, "explicit-socket-service")
168181
assert.Equal(t, &Service{
@@ -172,6 +185,7 @@ func TestSystemdFS(t *testing.T) {
172185
State: ServiceUnknown,
173186
Installed: true,
174187
Enabled: true,
188+
Static: true,
175189
}, servicesMap["explicit-socket-service"])
176190

177191
// Relative path symlink

0 commit comments

Comments
 (0)