Skip to content
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

providers: add initial zVM hypervisor support #865

Merged
merged 1 commit into from
Nov 4, 2019
Merged
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
1 change: 1 addition & 0 deletions doc/supported-platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Ignition is currently only supported for the following platforms:
* [Packet] - Ignition will read its configuration from the instance userdata. SSH keys are handled by coreos-metadata.
* [QEMU] - Ignition will read its configuration from the 'opt/com.coreos/config' key on the QEMU Firmware Configuration Device (available in QEMU 2.4.0 and higher).
* [DigitalOcean] - Ignition will read its configuration from the droplet userdata. SSH keys and network configuration are handled by coreos-metadata.
* [zVM] - Ignition will read its configuration from the reader device directly. The vmur program is necessary, which requires the vmcp and vmur kernel module as prerequisite, and the corresponding z/VM virtual unit record devices (in most cases 000c as reader, 000d as punch) must be set online.

Ignition is under active development so expect this list to expand in the coming months.

Expand Down
11 changes: 11 additions & 0 deletions internal/distro/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
mdadmCmd = "mdadm"
mountCmd = "mount"
sgdiskCmd = "sgdisk"
modprobeCmd = "modprobe"
udevadmCmd = "udevadm"
usermodCmd = "usermod"
useraddCmd = "useradd"
Expand All @@ -52,6 +53,11 @@ var (
vfatMkfsCmd = "mkfs.vfat"
xfsMkfsCmd = "mkfs.xfs"

//zVM programs
vmurCmd = "vmur"
chccwdevCmd = "chccwdev"
cioIgnoreCmd = "cio_ignore"

// Flags
selinuxRelabel = "true"
blackboxTesting = "false"
Expand All @@ -73,6 +79,7 @@ func GroupaddCmd() string { return groupaddCmd }
func MdadmCmd() string { return mdadmCmd }
func MountCmd() string { return mountCmd }
func SgdiskCmd() string { return sgdiskCmd }
func ModprobeCmd() string { return modprobeCmd }
func UdevadmCmd() string { return udevadmCmd }
func UsermodCmd() string { return usermodCmd }
func UseraddCmd() string { return useraddCmd }
Expand All @@ -84,6 +91,10 @@ func SwapMkfsCmd() string { return swapMkfsCmd }
func VfatMkfsCmd() string { return vfatMkfsCmd }
func XfsMkfsCmd() string { return xfsMkfsCmd }

func VmurCmd() string { return vmurCmd }
func ChccwdevCmd() string { return chccwdevCmd }
func CioIgnoreCmd() string { return cioIgnoreCmd }

func SelinuxRelabel() bool { return bakedStringToBool(selinuxRelabel) && !BlackboxTesting() }
func BlackboxTesting() bool { return bakedStringToBool(blackboxTesting) }
func WriteAuthorizedKeysFragment() bool {
Expand Down
5 changes: 5 additions & 0 deletions internal/platform/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/coreos/ignition/v2/internal/providers/qemu"
"github.com/coreos/ignition/v2/internal/providers/virtualbox"
"github.com/coreos/ignition/v2/internal/providers/vmware"
"github.com/coreos/ignition/v2/internal/providers/zvm"
"github.com/coreos/ignition/v2/internal/registry"
"github.com/coreos/ignition/v2/internal/resource"
)
Expand Down Expand Up @@ -132,6 +133,10 @@ func init() {
name: "metal",
fetch: noop.FetchConfig,
})
configs.Register(Config{
name: "zvm",
fetch: zvm.FetchConfig,
})
}

func Get(name string) (config Config, ok bool) {
Expand Down
109 changes: 109 additions & 0 deletions internal/providers/zvm/zvm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2019 Red Hat, Inc.
//
// 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.

// The zVM provider fetches a local configuration from the virtual unit
// record devices.

package zvm

import (
"bytes"
"fmt"
"io/ioutil"
"os/exec"
"strings"

"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/v3_1_experimental/types"
"github.com/coreos/ignition/v2/internal/distro"
"github.com/coreos/ignition/v2/internal/log"
"github.com/coreos/ignition/v2/internal/providers/util"
"github.com/coreos/ignition/v2/internal/resource"
"github.com/coreos/vcontext/report"
)

const readerDevice string = "000c"

func FetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) {
// Fetch config files directly from reader device.
_, err := f.Logger.LogCmd(exec.Command(distro.ModprobeCmd(), "vmur"), "Loading zVM control program module")
if err != nil {
f.Logger.Err("Couldn't install vmur module: %v", err)
errors := fmt.Errorf("Couldn't install vmur module: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: can probably dedupe these by assigning to a var first?
Edit: and same in other spots below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: can probably dedupe these by assigning to a var first?
Edit: and same in other spots below

Did you mean a function like printError() to do f.loggr.Err? I don't think printError should replace f.logger.Err to involve the context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just mean something like:

errmsg := fmt.Sprintf("Couldn't install vmur module: %v", err)
f.Logger.Err(errmsg)
errors := fmt.Errorf(errmsg)

return types.Config{}, report.Report{}, errors
}
// Online the reader device.
logger := f.Logger
err = onlineDevice(logger)
if err != nil {
return types.Config{}, report.Report{}, err
zhengxiaomei123 marked this conversation as resolved.
Show resolved Hide resolved
}
// Read files from the z/VM reader queue.
readerInfo, err := exec.Command(distro.VmurCmd(), "li").CombinedOutput()
if err != nil {
f.Logger.Err("Can not get reader device: %v", err)
errors := fmt.Errorf("Can not get reader device: %v", err)
return types.Config{}, report.Report{}, errors
}
for _, records := range strings.Split(string(readerInfo), "\n") {
record := strings.Fields(records)
// The records format: ORIGINID FILE CLASSA CLASSB RECORDS CPY HOLD DATE TIME NAME TYPE DIST
if len(record) <= 1 {
zhengxiaomei123 marked this conversation as resolved.
Show resolved Hide resolved
break
}
if len(record) < 11 {
zhengxiaomei123 marked this conversation as resolved.
Show resolved Hide resolved
continue
}
spoolid := record[1]
ftype := record[10]
zhengxiaomei123 marked this conversation as resolved.
Show resolved Hide resolved
file := record[9] + "." + ftype
// Receive the spool file.
if ftype == "ign" {
_, err := f.Logger.LogCmd(exec.Command(distro.VmurCmd(), "re", "-f", spoolid, file), "Receive the spool file")
if err != nil {
return types.Config{}, report.Report{}, err
}
f.Logger.Info("using config file at %q", file)
rawConfig, err := ioutil.ReadFile(file)
if err != nil {
f.Logger.Err("Couldn't read config from configFile %q: %v", file, err)
break
}
jsonConfig := bytes.Trim(rawConfig, string(byte(0)))
return util.ParseConfig(f.Logger, jsonConfig)
}
}
return types.Config{}, report.Report{}, errors.ErrEmpty
}

func onlineDevice(logger *log.Logger) error {
_, err := logger.LogCmd(exec.Command(distro.ChccwdevCmd(), "-e", readerDevice), "Brings a Linux device online")
if err != nil {
ajeddeloh marked this conversation as resolved.
Show resolved Hide resolved
zhengxiaomei123 marked this conversation as resolved.
Show resolved Hide resolved
// If online failed, expose the device firstly.
_, err = logger.LogCmd(exec.Command(distro.CioIgnoreCmd(), "-r", readerDevice), "Expose reader device")
if err != nil {
logger.Err("Couldn't expose reader device %q: %v", readerDevice, err)
errors := fmt.Errorf("Couldn't expose reader device %q: %v", readerDevice, err)
return errors
}
_, err = logger.LogCmd(exec.Command(distro.ChccwdevCmd(), "-e", readerDevice), "Brings a Linux device online")
if err != nil {
logger.Err("Couldn't online reader device")
errors := fmt.Errorf("Couldn't online reader device")
return errors
}
}
_, err = logger.LogCmd(exec.Command(distro.UdevadmCmd(), "settle"), "Settle udev device")
return err
}