rootio does not process the returned metadata from hegel correctly
alienninja opened this issue · 4 comments
I am using the hardware and template examples as outlined on the tinkerbell.org documentation page. I have found that when rootio requests metadata from hegel, it is expecting it in a format that is different from the Tinkerbell hardware json format. Rootio is looking for types.Metadata which, when comparing it to a Tinkerbell hardware json, is an instance within the metadata structure.
As a test, I modified a local copy of rootio to read in a Tinkerbell hardware json and return the correct metadata instance.
Expected Behaviour
Rootio should correctly parse the returned metadata and process the storage structure correctly.
Current Behaviour
Unmodified, rootio states that zero disks were found in the metadata.
Possible Solution
Configure rootio to process the metadata as a hardware json. Or modify the call to hegel to return the correct structure via something like /metadata/storage.
Steps to Reproduce (for bugs)
- Set up a docker-compose instance of Tinkerbell
- Create a hardware json as outlined on https://docs.tinkerbell.org/hardware-data/
- Create a template yaml as outlined on the bottom of https://docs.tinkerbell.org/deploying-operating-systems/examples-ubuntu/
- Run a pxeboot on the machine to be provisioned, review the rootio logs to show that it states zero disks found.
Context
I am unable to use rootio to process my storage array, this prevents me from using Tinkerbell as intended.
Your Environment
- Operating System and version (e.g. Linux, Windows, MacOS):
The provisioner is running Ubuntu 20.04 on a VM on ESXi. The machine being provisioned is on the same ESXi server. So both VM's. - How are you running Tinkerbell? Using Vagrant & VirtualBox, Vagrant & Libvirt, on Packet using Terraform, or give details:
Running Tinkerbell with docker-compose - Link to your project or a code example to reproduce issue:
Modifying rootio to read in the metadata into the following structure makes it work correctly:
I was able to limit all changes to rootio/v1/pkg/types.go/metadata.go
type ExportedCacher struct {
ID string `json:"id"`
Metadata Metadata `jsonm:"metadata"`
}
type Metadata struct {
Arch string `json:"arch"`
State string `json:"state"`
EFIBoot bool `json:"efi_boot"`
Instance Instance `json:"instance,omitempty"`
PreinstalledOperatingSystemVersion interface{} `json:"preinstalled_operating_system_version"`
NetworkPorts []map[string]interface{} `json:"network_ports"`
PlanSlug string `json:"plan_slug"`
Facility string `json:"facility_code"`
Hostname string `json:"hostname"`
BondingMode int `json:"bonding_mode"`
}
type Instance struct {
ID string `json:"id,omitempty"`
State string `json:"state,omitempty"`
Hostname string `json:"hostname,omitempty"`
AllowPXE bool `json:"allow_pxe,omitempty"`
Rescue bool `json:"rescue,omitempty"`
IPAddresses []map[string]interface{} `json:"ip_addresses,omitempty"`
OS OperatingSystem `json:"operating_system_version,omitempty"`
UserData string `json:"userdata,omitempty"`
CryptedRootPassword string `json:"crypted_root_password,omitempty"`
Storage Storage `json:"storage,omitempty"`
SSHKeys []string `json:"ssh_keys,omitempty"`
NetworkReady bool `json:"network_ready,omitempty"`
}
type OperatingSystem struct {
Slug string `json:"slug"`
Distro string `json:"distro"`
Version string `json:"version"`
ImageTag string `json:"image_tag"`
OsSlug string `json:"os_slug"`
}
type File struct {
Path string `json:"path"`
Contents string `json:"contents,omitempty"`
Mode int `json:"mode,omitempty"`
UID int `json:"uid,omitempty"`
GID int `json:"gid,omitempty"`
}
type FilesystemOptions struct {
Force bool `json:"force,omitempty"`
Options []string `json:"options,omitempty"`
}
type Raid struct {
Name string `json:"name"`
Level string `json:"level"`
Devices []string `json:"devices"`
Spares int `json:"spares,omitempty"`
}
type Storage struct {
Disks []Disk `json:"disks,omitempty"`
RAID []Raid `json:"raid,omitempty"`
Filesystems []Filesystem `json:"filesystems,omitempty"`
}
//Filesystem defines the organisation of a filesystem
type Filesystem struct {
Mount struct {
Create struct {
Options []string `json:"options"`
} `json:"create"`
Device string `json:"device"`
Format string `json:"format"`
Point string `json:"point"`
} `json:"mount"`
}
//Disk defines the configuration for a disk
type Disk struct {
Device string `json:"device"`
Partitions []Partitions `json:"partitions"`
WipeTable bool `json:"wipe_table"`
}
//Partitions details the architecture
type Partitions struct {
Label string `json:"label"`
Number int `json:"number"`
Size uint64 `json:"size"`
}
//I also configured RetreiveData to return the appropriate nested object:
func RetreieveData() (*Instance, error) {
metadataURL := os.Getenv("MIRROR_HOST")
if metadataURL == "" {
return nil, fmt.Errorf("Unable to discover the metadata server from environment variable [MIRROR_HOST]")
}
metadataClient := http.Client{
Timeout: time.Second * 60, // Timeout after 60 seconds (seems massively long is this dial-up?)
}
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:50061/metadata", metadataURL), nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "bootkit")
res, getErr := metadataClient.Do(req)
if getErr != nil {
return nil, err
}
if res.Body != nil {
defer res.Body.Close()
}
body, readErr := ioutil.ReadAll(res.Body)
if readErr != nil {
return nil, err
}
var exportedcacher ExportedCacher
//var mdata Metadata
jsonErr := json.Unmarshal(body, &exportedcacher)
if jsonErr != nil {
return nil, jsonErr
}
return &exportedcacher.Metadata.Instance, nil
}
Hi @alienninja, what is rootio? Can you give me a link as I'm not familiar with it.
Hi @alienninja, what is rootio? Can you give me a link as I'm not familiar with it.
Sure! It's one of the actions provided in tinkerbell.
https://github.com/tinkerbell/hub/tree/main/actions/rootio/v1
oh! 🤦 :D
Hi everyone, I really wanted to get this working so I forked and modified the rootio code to read in the template json file as it's spec'd from the Tinkerbell documentation. This is now working for me, but I think there may be a better way to reference the correct structure rather than manually copying into the code
Also -- rootio doesn't create /etc/fstab, which makes sense because this is before the archive2disk is run. I was thinking an fstab action is needed that could read in the metadata and generate fstab since all the needed data is in metadata. I realized this when my root was mounted as read only after the provisioning.
my fork:
https://github.com/alienninja/hub/tree/main/actions/rootio/v1