diff --git a/example/httpboot_config.yaml b/example/httpboot_config.yaml new file mode 100644 index 0000000..cc00eab --- /dev/null +++ b/example/httpboot_config.yaml @@ -0,0 +1 @@ +bootServer: http://[2001:db8::1]/image.uki \ No newline at end of file diff --git a/internal/api/httpboot_config.go b/internal/api/httpboot_config.go new file mode 100644 index 0000000..df61e29 --- /dev/null +++ b/internal/api/httpboot_config.go @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: MIT + +package api + +type HttpBootConfig struct { + BootServer string `yaml:"bootServer"` +} diff --git a/plugins/httpboot/custom_httpboot_config.yaml b/plugins/httpboot/custom_httpboot_config.yaml new file mode 100644 index 0000000..3f14053 --- /dev/null +++ b/plugins/httpboot/custom_httpboot_config.yaml @@ -0,0 +1 @@ +bootServer: "bootservice:http://[::1]:8888/httpboot" \ No newline at end of file diff --git a/plugins/httpboot/httpboot_config.yaml b/plugins/httpboot/httpboot_config.yaml new file mode 100644 index 0000000..cce8035 --- /dev/null +++ b/plugins/httpboot/httpboot_config.yaml @@ -0,0 +1 @@ +bootServer: "https://[2001:db8::1]/boot.uki" \ No newline at end of file diff --git a/plugins/httpboot/malformed_httpboot_config.yaml b/plugins/httpboot/malformed_httpboot_config.yaml new file mode 100644 index 0000000..69e8440 --- /dev/null +++ b/plugins/httpboot/malformed_httpboot_config.yaml @@ -0,0 +1 @@ +bootServer: ftp://www.example.com/boot.uki \ No newline at end of file diff --git a/plugins/httpboot/plugin.go b/plugins/httpboot/plugin.go index bf621b1..264ed48 100644 --- a/plugins/httpboot/plugin.go +++ b/plugins/httpboot/plugin.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/url" + "os" "strings" "github.com/coredhcp/coredhcp/handler" @@ -17,6 +18,8 @@ import ( "github.com/coredhcp/coredhcp/plugins" "github.com/insomniacslk/dhcp/dhcpv4" "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/ironcore-dev/fedhcp/internal/api" + "gopkg.in/yaml.v2" ) var bootFile4 string @@ -33,11 +36,19 @@ var Plugin = plugins.Plugin{ const httpClient = "HTTPClient" -func parseArgs(args ...string) (*url.URL, bool, error) { +func parseArgs(args ...string) (string, error) { if len(args) != 1 { - return nil, false, fmt.Errorf("exactly one argument must be passed to the httpboot plugin, got %d", len(args)) + return "", fmt.Errorf("exactly one argument must be passed to the httpboot plugin, got %d", len(args)) } - arg := args[0] + return args[0], nil +} + +func parseConfig(args ...string) (*url.URL, bool, error) { + httpbootConfig, err := loadConfig(args...) + if err != nil { + return nil, false, fmt.Errorf("erorr loading httpboot plugin config: %v", err) + } + arg := httpbootConfig.BootServer useBootService := strings.HasPrefix(arg, "bootservice:") if useBootService { arg = strings.TrimPrefix(arg, "bootservice:") @@ -52,8 +63,26 @@ func parseArgs(args ...string) (*url.URL, bool, error) { return parsedURL, useBootService, nil } +func loadConfig(args ...string) (*api.HttpBootConfig, error) { + path, err := parseArgs(args...) + if err != nil { + return nil, fmt.Errorf("invalid configuration: %v", err) + } + + log.Debugf("Reading httpboot config file %s", path) + configData, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to read config file: %v", err) + } + config := &api.HttpBootConfig{} + if err = yaml.Unmarshal(configData, config); err != nil { + return nil, fmt.Errorf("failed to parse config file: %v", err) + } + return config, nil +} + func setup6(args ...string) (handler.Handler6, error) { - u, ubs, err := parseArgs(args...) + u, ubs, err := parseConfig(args...) if err != nil { return nil, fmt.Errorf("invalid configuration: %v", err) } @@ -64,7 +93,7 @@ func setup6(args ...string) (handler.Handler6, error) { } func setup4(args ...string) (handler.Handler4, error) { - u, ubs, err := parseArgs(args...) + u, ubs, err := parseConfig(args...) if err != nil { return nil, fmt.Errorf("invalid configuration: %v", err) } diff --git a/plugins/httpboot/plugin_test.go b/plugins/httpboot/plugin_test.go index 53cee9b..7e14aa7 100644 --- a/plugins/httpboot/plugin_test.go +++ b/plugins/httpboot/plugin_test.go @@ -31,18 +31,20 @@ const ( ) var ( - expectedHTTPClient = []byte("HTTPClient") + expectedHTTPClient = []byte("HTTPClient") + httpbootFilePath = []string{"httpboot_config.yaml"} + customHttpbootFilePath = []string{"custom_httpboot_config.yaml"} ) -func Init4(bootURL string) { - _, err := setup4(bootURL) +func Init4(bootFileUrl ...string) { + _, err := setup4(bootFileUrl...) if err != nil { log.Fatal(err) } } -func Init6(bootURL string) { - _, err := setup6(bootURL) +func Init6(bootFileUrl ...string) { + _, err := setup6(bootFileUrl...) if err != nil { log.Fatal(err) } @@ -51,12 +53,12 @@ func Init6(bootURL string) { /* parametrization */ func TestWrongNumberArgs(t *testing.T) { - _, _, err := parseArgs("foo", "bar") + _, err := parseArgs("foo", "bar") if err == nil { t.Fatal("no error occurred when providing wrong number of args (2), but it should have") } - _, _, err = parseArgs() + _, err = parseArgs() if err == nil { t.Fatal("no error occurred when providing wrong number of args (0), but it should have") } @@ -69,12 +71,13 @@ func TestWrongArgs(t *testing.T) { "bootfail:https://www.example.com/boot.uki", "bootservice:tftp://www.example.com/boot.uki"} + malformedHttpbootFilePath := []string{"malformed_httpboot_config.yaml"} for _, wrongURL := range malformedBootURL { - _, err := setup4(wrongURL) + _, err := setup4(malformedHttpbootFilePath...) if err == nil { t.Fatalf("no error occurred when parsing wrong boot param %s, but it should have", wrongURL) } - _, err = setup6(wrongURL) + _, err = setup6(malformedHttpbootFilePath...) if err == nil { t.Fatalf("no error occurred when parsing wrong boot param %s, but it should have", wrongURL) } @@ -83,7 +86,7 @@ func TestWrongArgs(t *testing.T) { /* IPv6 */ func TestGenericHTTPBootRequested6(t *testing.T) { - Init6(expectedGenericBootURL) + Init6(httpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { @@ -141,7 +144,7 @@ func TestGenericHTTPBootRequested6(t *testing.T) { } func TestMalformedHTTPBootRequested6(t *testing.T) { - Init6(expectedGenericBootURL) + Init6(httpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { @@ -210,7 +213,7 @@ func TestMalformedHTTPBootRequested6(t *testing.T) { } func TestHTTPBootNotRequested6(t *testing.T) { - Init6(expectedGenericBootURL) + Init6(httpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { @@ -251,7 +254,7 @@ func TestHTTPBootNotRequested6(t *testing.T) { } func TestHTTPBootNotRelayedMsg6(t *testing.T) { - Init6(expectedGenericBootURL) + Init6(httpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { @@ -287,7 +290,7 @@ func TestHTTPBootNotRelayedMsg6(t *testing.T) { /* IPv4 */ func TestGenericHTTPBootRequested4(t *testing.T) { - Init4(expectedGenericBootURL) + Init4(httpbootFilePath...) req, err := dhcpv4.NewDiscovery(net.HardwareAddr{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, @@ -325,7 +328,7 @@ func TestGenericHTTPBootRequested4(t *testing.T) { } func TestMalformedHTTPBootRequested4(t *testing.T) { - Init4(expectedGenericBootURL) + Init4(httpbootFilePath...) req, err := dhcpv4.NewDiscovery(net.HardwareAddr{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, @@ -393,7 +396,7 @@ func TestMalformedHTTPBootRequested4(t *testing.T) { } func TestHTTPBootNotRequested4(t *testing.T) { - Init4(expectedGenericBootURL) + Init4(httpbootFilePath...) req, err := dhcpv4.NewDiscovery(net.HardwareAddr{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, @@ -434,7 +437,7 @@ func TestCustomHTTPBootRequestedKnownIP(t *testing.T) { go startBootServiceMock() time.Sleep(time.Second * 1) - Init6(fmt.Sprintf(bootServiceEndpoint, bootServicePort)) + Init6(customHttpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { t.Fatal(err) @@ -570,7 +573,7 @@ func TestCustomHTTPBootRequestedUnknownClient(t *testing.T) { } func createHTTPBootRequest(t *testing.T) (error, *dhcpv6.RelayMessage) { - Init6(fmt.Sprintf(bootServiceEndpoint, bootServicePort)) + Init6(customHttpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil { t.Fatal(err) @@ -596,7 +599,7 @@ func createHTTPBootRequest(t *testing.T) (error, *dhcpv6.RelayMessage) { } func TestNoRelayCustomHTTPBootRequested(t *testing.T) { - Init6(fmt.Sprintf(bootServiceEndpoint, bootServicePort)) + Init6(customHttpbootFilePath...) req, err := dhcpv6.NewMessage() if err != nil {