build:create systemd_journald stage
Creates new stage to configure journald to persist the journal. Instead of creating the `/var/log/journal` directory we explicitly configure journald via the new stage.This is done in according to the FCOS norms. Unit tests also added for functionality check. Co-authored-by: Irene Diez <idiez@redhat.com> Signed-off-by: Sayan Paul <saypaul@redhat.com>
This commit is contained in:
parent
8c75975917
commit
5ce3de214d
2 changed files with 162 additions and 0 deletions
92
internal/osbuild/systemd_journald_stage.go
Normal file
92
internal/osbuild/systemd_journald_stage.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package osbuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const configFilenameRegex = "^[a-zA-Z0-9_\\.-]{1,250}\\.conf$"
|
||||
|
||||
type SystemdJournaldStageOptions struct {
|
||||
Filename string `json:"filename"`
|
||||
Config SystemdJournaldConfigDropin `json:"config"`
|
||||
}
|
||||
|
||||
func (SystemdJournaldStageOptions) isStageOptions() {}
|
||||
|
||||
func (o SystemdJournaldStageOptions) validate() error {
|
||||
filenameRegex := regexp.MustCompile(configFilenameRegex)
|
||||
if !filenameRegex.MatchString(o.Filename) {
|
||||
return fmt.Errorf("filename %q doesn't conform to schema (%s)", o.Filename, repoFilenameRegex)
|
||||
}
|
||||
if o.Config.Journal == (SystemdJournaldConfigJournalSection{}) {
|
||||
return fmt.Errorf("the 'Journal' section is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSystemdJournaldStage(options *SystemdJournaldStageOptions) *Stage {
|
||||
if err := options.validate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &Stage{
|
||||
Type: "org.osbuild.systemd-journald",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
type SystemdJournaldConfigDropin struct {
|
||||
Journal SystemdJournaldConfigJournalSection `json:"Journal"`
|
||||
}
|
||||
|
||||
type ConfigStorage string
|
||||
|
||||
const (
|
||||
StorageVolatile ConfigStorage = "volatile"
|
||||
StoragePresistent ConfigStorage = "persistent"
|
||||
StorageAuto ConfigStorage = "auto"
|
||||
StorageNone ConfigStorage = "none"
|
||||
)
|
||||
|
||||
type ConfigSplitMode string
|
||||
|
||||
const (
|
||||
SplitUuid ConfigSplitMode = "uuid"
|
||||
SplitNone ConfigSplitMode = "none"
|
||||
)
|
||||
|
||||
type ConfigAudit string
|
||||
|
||||
const (
|
||||
AuditYes ConfigAudit = "yes"
|
||||
AuditNo ConfigAudit = "no"
|
||||
)
|
||||
|
||||
// 'Journal' configuration section, at least one option must be specified
|
||||
type SystemdJournaldConfigJournalSection struct {
|
||||
// Controls where to store journal data.
|
||||
Storage ConfigStorage `json:"Storage,omitempty"`
|
||||
|
||||
// Sets whether the data objects stored in the journal should be
|
||||
// compressed or not. Can also take threshold values.
|
||||
Compress string `json:"Compress,omitempty"`
|
||||
|
||||
// Splits journal files per user or to a single file.
|
||||
SplitMode ConfigSplitMode `json:"SplitMode,omitempty"`
|
||||
|
||||
// Max time to store entries in a single file. By default seconds, may be
|
||||
// sufixed with units (year, month, week, day, h, m) to override this.
|
||||
MaxFileSec string `json:"MaxFileSec,omitempty"`
|
||||
|
||||
// Maximum time to store journal entries. By default seconds, may be sufixed
|
||||
// with units (year, month, week, day, h, m) to override this.
|
||||
MaxRetentionSec string `json:"MaxRetentionSec,omitempty"`
|
||||
|
||||
// Timeout before synchronizing journal files to disk. Minimum 0.
|
||||
SyncIntervalSec int `json:"SyncIntervalSec,omitempty"`
|
||||
|
||||
// Enables/Disables kernel auditing on start-up, leaves it as is if
|
||||
// unspecified.
|
||||
Audit ConfigAudit `json:"Audit,omitempty"`
|
||||
}
|
||||
70
internal/osbuild/systemd_journald_stage_test.go
Normal file
70
internal/osbuild/systemd_journald_stage_test.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package osbuild
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSystemdJournalStage(t *testing.T) {
|
||||
options := &SystemdJournaldStageOptions{
|
||||
Filename: "journald-config.conf",
|
||||
Config: SystemdJournaldConfigDropin{
|
||||
Journal: SystemdJournaldConfigJournalSection{
|
||||
Storage: StoragePresistent,
|
||||
Compress: "yes",
|
||||
MaxFileSec: "10day",
|
||||
Audit: AuditYes,
|
||||
},
|
||||
}}
|
||||
expectedStage := &Stage{
|
||||
Type: "org.osbuild.systemd-journald",
|
||||
Options: options,
|
||||
}
|
||||
actualStage := NewSystemdJournaldStage(options)
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
||||
func TestSystemdJournaldStage_ValidateInvalid(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
options SystemdJournaldStageOptions
|
||||
}{
|
||||
{
|
||||
name: "empty-options",
|
||||
options: SystemdJournaldStageOptions{},
|
||||
},
|
||||
{
|
||||
name: "no-journal-section-options",
|
||||
options: SystemdJournaldStageOptions{
|
||||
Filename: "10-some-file.conf",
|
||||
Config: SystemdJournaldConfigDropin{
|
||||
Journal: SystemdJournaldConfigJournalSection{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for idx, te := range tests {
|
||||
t.Run(te.name, func(t *testing.T) {
|
||||
assert.Errorf(t, te.options.validate(), "%q didn't return an error [idx: %d]", te.name, idx)
|
||||
assert.Panics(t, func() { NewSystemdJournaldStage(&te.options) })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidFilename(t *testing.T) {
|
||||
options := &SystemdJournaldStageOptions{
|
||||
Filename: "invalid-filename",
|
||||
Config: SystemdJournaldConfigDropin{
|
||||
Journal: SystemdJournaldConfigJournalSection{
|
||||
Storage: StoragePresistent,
|
||||
Compress: "yes",
|
||||
MaxFileSec: "10day",
|
||||
Audit: AuditYes,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Errorf(t, options.validate(), "test didn't return any error ")
|
||||
assert.Panics(t, func() { NewSystemdJournaldStage(options) })
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue