Skip to content

Provide platform to DI #750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 21 additions & 44 deletions plugins/platformdetect/platform_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,15 @@ import (
"slices"

"github.com/untangle/golang-shared/plugins"
"github.com/untangle/golang-shared/plugins/types"
"github.com/untangle/golang-shared/services/settings"
)

// HostType is a externally-opaque type for declaring a host
// type.
type HostType struct {
indicatorFilename string
name string
}

var (
EOS = HostType{
indicatorFilename: "/etc/Eos-release",
name: "Eos",
}
OpenWrt = HostType{
indicatorFilename: "/etc/openwrt_version",
name: "OpenWrt",
}
Unclassified = HostType{
indicatorFilename: "",
name: "Unclassified",
}
)

// PlatformFilter is a plugin predicate (declared in
// golang-shared/plugins) which filters out plugins that have
// PluginSpec metadata and don't apply to the current platform.
type PlatformFilter struct {
currentPlatform HostType
currentPlatform types.Platform
}

// PlatformSpec is a specification of the platforms that apply to a
Expand All @@ -50,31 +29,28 @@ type PlatformFilter struct {
// empty (just don't supply a PlatformSpec in this case) but if they
// are, the plugin will be run.
type PlatformSpec struct {
OnlyOn []HostType
Excludes []HostType
OnlyOn []types.Platform
Excludes []types.Platform
}

// NewPlatformFilter creates a new platform filter, during
// construction we determine the platform from the filesystem.
func NewPlatformFilter(fs fs.StatFS) *PlatformFilter {
platforms := []HostType{
EOS,
OpenWrt,
Unclassified,
}
filter := &PlatformFilter{
currentPlatform: Unclassified,
}
for _, plat := range platforms {
if settings.FileExistsInFS(plat.indicatorFilename, fs) {
filter.currentPlatform = plat
return filter
// Determines the platform by looking at the provided FS
// for specific files.
func GetCurrentPlatform(fs fs.StatFS) types.Platform {
for _, plat := range types.Platforms {
if settings.FileExistsInFS(plat.IndicatorFilename, fs) {
return plat
}
}
return filter
return types.Unclassified
}

// NewPlatformFilter creates a new platform filter, during
// construction we determine the platform from the filesystem.
func NewPlatformFilter(platform types.Platform) *PlatformFilter {
return &PlatformFilter{currentPlatform: platform}
}

// IsRelevant implements the golang-shared plugins.PluginPredicate
// IsRelevant implements the golang-shared types.PluginPredicate
// interface and only returns true when the current platform is supported.
func (pf *PlatformFilter) IsRelevant(pc plugins.PluginConstructor, metadata ...any) bool {
for _, i := range metadata {
Expand All @@ -89,9 +65,10 @@ func (pf *PlatformFilter) IsRelevant(pc plugins.PluginConstructor, metadata ...a
spec.Excludes))

}
if len(spec.OnlyOn) > 0 && !slices.Contains(spec.OnlyOn, pf.currentPlatform) {
platformMatch := func(p types.Platform) bool { return p.Equals(pf.currentPlatform) }
if len(spec.OnlyOn) > 0 && !slices.ContainsFunc(spec.OnlyOn, platformMatch) {
return false
} else if len(spec.Excludes) > 0 && slices.Contains(spec.Excludes, pf.currentPlatform) {
} else if len(spec.Excludes) > 0 && slices.ContainsFunc(spec.Excludes, platformMatch) {
return false
}
}
Expand Down
41 changes: 21 additions & 20 deletions plugins/platformdetect/platform_detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing/fstest"

"github.com/untangle/golang-shared/plugins"
"github.com/untangle/golang-shared/plugins/types"
)

func TestPlatformFilter(t *testing.T) {
Expand All @@ -14,64 +15,64 @@ func TestPlatformFilter(t *testing.T) {
files []string
metadata []any
expected bool
currentPlatform HostType
currentPlatform types.Platform
}{
{
name: "EOS platform, no metadata",
files: []string{EOS.indicatorFilename},
files: []string{types.EOS.IndicatorFilename},
metadata: nil,
expected: true,
currentPlatform: EOS,
currentPlatform: types.EOS,
},
{
name: "OpenWrt platform, no metadata",
files: []string{OpenWrt.indicatorFilename},
files: []string{types.OpenWrt.IndicatorFilename},
metadata: nil,
expected: true,
currentPlatform: OpenWrt,
currentPlatform: types.OpenWrt,
},
{
name: "Unclassified platform, no metadata",
files: []string{},
metadata: nil,
expected: true,
currentPlatform: Unclassified,
currentPlatform: types.Unclassified,
},
{
name: "EOS platform, only on EOS",
files: []string{EOS.indicatorFilename},
files: []string{types.EOS.IndicatorFilename},
metadata: []any{PlatformSpec{
OnlyOn: []HostType{EOS},
OnlyOn: []types.Platform{types.EOS},
}},
expected: true,
currentPlatform: EOS,
currentPlatform: types.EOS,
},
{
name: "EOS platform, only on OpenWrt",
files: []string{EOS.indicatorFilename},
files: []string{types.EOS.IndicatorFilename},
metadata: []any{PlatformSpec{
OnlyOn: []HostType{OpenWrt},
OnlyOn: []types.Platform{types.OpenWrt},
}},
expected: false,
currentPlatform: EOS,
currentPlatform: types.EOS,
},
{
name: "OpenWrt platform, excludes OpenWrt",
files: []string{OpenWrt.indicatorFilename},
files: []string{types.OpenWrt.IndicatorFilename},
metadata: []any{PlatformSpec{
Excludes: []HostType{OpenWrt},
Excludes: []types.Platform{types.OpenWrt},
}},
expected: false,
currentPlatform: OpenWrt,
currentPlatform: types.OpenWrt,
},
{
name: "No platform match",
files: []string{"/etc/something_else"},
metadata: []any{PlatformSpec{
OnlyOn: []HostType{OpenWrt},
OnlyOn: []types.Platform{types.OpenWrt},
}},
expected: false,
currentPlatform: Unclassified,
currentPlatform: types.Unclassified,
},
}

Expand All @@ -87,11 +88,11 @@ func TestPlatformFilter(t *testing.T) {
fs[f[1:]] = &fstest.MapFile{}
}

filter := NewPlatformFilter(fs)
filter := NewPlatformFilter(GetCurrentPlatform(fs))

if filter.currentPlatform != tt.currentPlatform {
if filter.currentPlatform.Name != tt.currentPlatform.Name {
t.Errorf("Incorrect platform detected. Expected %s, got %s",
tt.currentPlatform.name, filter.currentPlatform.name)
tt.currentPlatform.Name, filter.currentPlatform.Name)
}

var pc plugins.PluginConstructor
Expand Down
55 changes: 55 additions & 0 deletions plugins/types/platform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package types

// HostType is a externally-opaque type for declaring a host
// type.
type Platform struct {
IndicatorFilename string
Name string

// Path settings files should be looked up in
SettingsDirPath string

// Files that have a unique mapping on the platform.
// The mapping goes from the openWRT equivalent file
// to it's platform specific file location.
AdditionalFileMappings map[string]string
}

// Equals checks if two platforms are equal. Simply
// compares their names
func (p *Platform) Equals(other Platform) bool {
return p.Name == other.Name
}

var (
EOS = Platform{
IndicatorFilename: "/etc/Eos-release",
Name: "Eos",
SettingsDirPath: "/mnt/flash/mfw-settings",
AdditionalFileMappings: map[string]string{
"/etc/config/categories.json": "/usr/share/bctid/categories.json",
},
}
OpenWrt = Platform{
IndicatorFilename: "/etc/openwrt_version",
Name: "OpenWrt",
SettingsDirPath: "/etc/config",
}
Vittoria = Platform{
IndicatorFilename: "/notknown/",
Name: "Unclassified",
SettingsDirPath: "/velocloud/",
}
Unclassified = Platform{
IndicatorFilename: "",
Name: "Unclassified",
SettingsDirPath: "",
}

Platforms = []Platform{
EOS,
OpenWrt,
Vittoria,
Unclassified,
}
)
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"name":"untangle-node-sitefilter","allowedState":0},{"name":"untangle-node-classd","allowedState":1},{"name":"untangle-node-dynamic-lists","allowedState":0},{"name":"untangle-node-dns-filter","allowedState":0},{"name":"untangle-node-dos-filter","allowedState":0},{"name":"untangle-node-threat-prevention","allowedState":1},{"name":"untangle-node-geoip","allowedState":0},{"name":"untangle-node-captiveportal","allowedState":0},{"name":"untangle-node-discovery","allowedState":0}]
[{"name":"untangle-node-geoip","allowedState":0},{"name":"untangle-node-classd","allowedState":1},{"name":"untangle-node-dos-filter","allowedState":0},{"name":"untangle-node-threat-prevention","allowedState":1},{"name":"untangle-node-dynamic-lists","allowedState":0},{"name":"untangle-node-sitefilter","allowedState":0},{"name":"untangle-node-captiveportal","allowedState":0},{"name":"untangle-node-discovery","allowedState":0},{"name":"untangle-node-dns-filter","allowedState":0}]
66 changes: 29 additions & 37 deletions services/settings/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,24 @@ import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"

"github.com/untangle/golang-shared/plugins/types"
)

// FilenameLocator finds files on the local filesystem, allowing the
// system to be EOS or OpenWrt mode and concealing the
// differences.
type FilenameLocator struct {
fileExists func(filename string) bool
platform types.Platform
}

const (
// Present of file indicates we are in native mode
nativeEOSIndicatorFile = "/etc/efw-version"

// Standard prefix for native EOS
nativeEOSPrefix = "/mnt/flash/mfw-settings/"

// Standard prefix for OpenWRT
openWRTPrefix = "/etc/config/"
)

var openWRTFileToNativeEOS = map[string]string{
"/etc/config/categories.json": "/usr/share/bctid/categories.json",
func NewFilenameLocator(platform types.Platform) *FilenameLocator {
return &FilenameLocator{
fileExists: FileExists,
}
}

// NoFileAtPath is an error for if a file doesn't exist. In this case
Expand Down Expand Up @@ -83,39 +78,36 @@ func FileExistsInFS(fname string, fs fs.StatFS) bool {
// it assumes that called uses default to OpenWRT platform. Only paths in mappings or paths which
// starts with /etc/config are translated.
func (f *FilenameLocator) getPlatformFileName(filename string) (string, error) { // Check if we are in native mode, most likely since there is only native and OpenWRT mode
if f.fileExists(nativeEOSIndicatorFile) { // In EOS mode, try mapping
if nativePath, exists := openWRTFileToNativeEOS[filename]; exists {
if !f.fileExists(nativePath) {
return nativePath, &NoFileAtPath{name: nativePath}
} else {
return nativePath, nil
}
// Still on EOS, if file contains /etc/config then translate, otherwise return
} else if strings.Contains(filename, openWRTPrefix) {
nativePath := nativeEOSPrefix + filename[strings.LastIndex(filename, "/")+1:]

if !f.fileExists(nativePath) {
return nativePath, &NoFileAtPath{name: nativePath}
} else {
return nativePath, nil
}
}
// File lookups are mapped from the OpenWRT filenames. No additional translation needed.
fmt.Printf("\n wat \n")
if f.platform.Equals(types.OpenWrt) {
return filename, nil
}
// On OpenWRT or no translation needed
if !f.fileExists(filename) {
return filename, &NoFileAtPath{name: filename}

if nativePath, ok := f.platform.AdditionalFileMappings[filename]; ok {
fmt.Printf("\nadditional mappings\n")
if !f.fileExists(nativePath) {
return nativePath, &NoFileAtPath{name: nativePath}
} else {
return nativePath, nil
}
} else if strings.Contains(filename, types.OpenWrt.SettingsDirPath) {
nativePath := filepath.Join(f.platform.SettingsDirPath, filename[strings.LastIndex(filename, "/")+1:])

if !f.fileExists(nativePath) {
return nativePath, &NoFileAtPath{name: nativePath}
} else {
return nativePath, nil
}
}

return filename, nil
}

// LocateFile locates the input filename on the filesystem,
// automatically translating it to EOS filenames when needed.
func (f *FilenameLocator) LocateFile(filename string) (string, error) {
if f.fileExists(filename) {
return filename, nil
}
return f.getPlatformFileName(filename)

}

var defaultLocator = &FilenameLocator{
Expand Down
Loading