forked from coreos/ignition
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Read the Ignition config from the Hyper-V Data Exchange Service ("KVP"), which can be configured on the host via WMI. KVP on Linux is normally handled by a combination of a kernel module (hv_utils) and a daemon shipped with the kernel source (hv_kvp_daemon). The latter writes world-readable files to /var/lib/hyperv; these contain an array of binary structs. The host-guest protocol has the guest OS as the passive peer; hv_kvp_daemon connects and is sent all the host's key-value pairs. We don't want to require hv_kvp_daemon as a dependency, so we use a pure Go reimplementation (libhvee) that supports just enough of the protocol to receive the KVPs. However, if we disconnect and then hv_kvp_daemon reconnects later, the host won't re-send the KVPs, so we also need to save them to /var/lib/hyperv in the same format used by the daemon. Unlike the daemon, we set the files to mode 600, since the Ignition config is potentially sensitive; the daemon does not change the permissions of existing files. Small configs can be stored in the `ignition.config` KVP. However, individual values have severe length limitations (~1 KiB of UTF-8), so we also support concatenating `ignition.config.0`, `ignition.config.1`, etc. to form a larger config. See also: coreos/fedora-coreos-tracker#1411 coreos/fedora-coreos-tracker#1424 Almost all of this work was done by Brent Baude; I just added the final polish. Thanks Brent! Co-authored-by: Brent Baude <[email protected]>
- Loading branch information
Showing
11 changed files
with
616 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Copyright 2023 Red Hat | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package hyperv | ||
|
||
import ( | ||
"fmt" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
"github.com/containers/libhvee/pkg/kvp" | ||
"github.com/coreos/ignition/v2/config/shared/errors" | ||
"github.com/coreos/ignition/v2/config/v3_5_experimental/types" | ||
"github.com/coreos/ignition/v2/internal/distro" | ||
"github.com/coreos/ignition/v2/internal/platform" | ||
"github.com/coreos/ignition/v2/internal/providers/util" | ||
"github.com/coreos/ignition/v2/internal/resource" | ||
"github.com/coreos/vcontext/report" | ||
) | ||
|
||
const singleKey = "ignition.config" | ||
|
||
// Prefix for multiple config fragments to reassemble. The suffix is a | ||
// sequential integer starting from 0. | ||
const splitKeyPrefix = "ignition.config." | ||
|
||
func init() { | ||
platform.Register(platform.Provider{ | ||
Name: "hyperv", | ||
FetchWithFiles: fetchConfig, | ||
}) | ||
} | ||
|
||
func fetchConfig(f *resource.Fetcher) ([]types.File, types.Config, report.Report, error) { | ||
var kvpFiles []types.File | ||
|
||
// To read key-value pairs from the Windows host, the hv_util kernel | ||
// module must be loaded to create the kernel device | ||
_, err := f.Logger.LogCmd(exec.Command(distro.ModprobeCmd(), "hv_utils"), "loading hv_utils kernel module") | ||
if err != nil { | ||
return nil, types.Config{}, report.Report{}, fmt.Errorf("loading hv_utils kernel module: %w", err) | ||
} | ||
|
||
keyValuePairs, err := kvp.GetKeyValuePairs() | ||
if err != nil { | ||
return nil, types.Config{}, report.Report{}, fmt.Errorf("reading key-value pairs: %w", err) | ||
} | ||
|
||
var ign string | ||
for _, kv := range keyValuePairs[kvp.DefaultKVPPoolID] { | ||
if kv.Key == singleKey { | ||
f.Logger.Debug("found single KVP key") | ||
ign = kv.Value | ||
break | ||
} | ||
} | ||
|
||
if ign == "" { | ||
ign, _, err = keyValuePairs.GetSplitKeyValues(splitKeyPrefix, kvp.DefaultKVPPoolID) | ||
if err == nil { | ||
f.Logger.Debug("found concatenated KVP keys") | ||
} else if err != kvp.ErrNoKeyValuePairsFound { | ||
return nil, types.Config{}, report.Report{}, fmt.Errorf("reassembling split config: %w", err) | ||
} | ||
} | ||
|
||
// hv_kvp_daemon writes pools to the filesystem in /var/lib/hyperv. | ||
// We've already read the pool data, and the host won't send it again | ||
// on this boot, so we need to write the files ourselves. | ||
for poolID := range keyValuePairs { | ||
// hv_kvp_daemon writes the pool files with mode 644 in a | ||
// directory with mode 755. This isn't safe for us, since | ||
// it leaks the config to non-root users, including on | ||
// subsequent boots. | ||
// - There's no API that lets us delete the KVPs from the host. | ||
// - We could filter out the KVPs when writing the pools, | ||
// but if hv_kvp_daemon runs on subsequent boots, it could | ||
// re-add them. | ||
// - The caller doesn't give us a way to create directory | ||
// entries, only files; and we probably shouldn't set | ||
// restrictive permissions on /var/lib/hyperv because it | ||
// hypothetically might be used for other purposes. | ||
// Avoid the issue by setting the files to mode 600. | ||
// hv_kvp_daemon won't change the mode afterward. | ||
poolPath := filepath.Join(kvp.DefaultKVPFilePath, fmt.Sprintf("%s%d", kvp.DefaultKVPBaseName, poolID)) | ||
kvpFiles = append(kvpFiles, util.MakeProviderOutputFile(poolPath, 0600, keyValuePairs.EncodePoolFile(poolID))) | ||
} | ||
|
||
if ign == "" { | ||
return kvpFiles, types.Config{}, report.Report{}, errors.ErrEmpty | ||
} | ||
|
||
c, r, err := util.ParseConfig(f.Logger, []byte(ign)) | ||
return kvpFiles, c, r, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.