Skip to content

Commit

Permalink
Use nbdkit for direct stream for the http importer (#1508)
Browse files Browse the repository at this point in the history
* Add nbdkit with qemu-img

Nbdkit can be used to stream directly the content of the image together
with qemu-img. It supports different plugins and filters.

Signed-off-by: Alice Frosi <afrosi@redhat.com>

* Use nbdkit to the http importer

Add nbdkit to stream directly the image content avoiding the scratch
space for the http importer.

Signed-off-by: Alice Frosi <afrosi@redhat.com>

* Adjust functional test cases with nbdkit

With the introduction of nbdkit, certain error messages do not match anymore,
and needed to be adjusted to the new behavior.

The scratch space is not needed anymore when the source is http for the majority of the cases.
Certain test cases checked the use of the scratch space, and those are not valid anymore.

Signed-off-by: Alice Frosi <afrosi@redhat.com>
  • Loading branch information
alicefr committed Jan 15, 2021
1 parent c2c6e2e commit f33abe6
Show file tree
Hide file tree
Showing 11 changed files with 491 additions and 67 deletions.
47 changes: 45 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,31 @@ http_file(
],
)

http_file(
name = "nbdkit-xz-filter",
sha256 = "a77043f110496658d87332b064f34fc10bbf0fdd429c4bbbe9542308ff087007",
urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/n/nbdkit-xz-filter-1.22.3-2.fc33.x86_64.rpm",
],
)

http_file(
name = "nbdkit-gzip-filter",
sha256 = "52787fd9aff69599837328b8b8dd76376999e7c5c96bd72669b0c77a1ac31d4f",
urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/n/nbdkit-gzip-filter-1.22.3-2.fc33.x86_64.rpm",
],
)

http_file(
name = "nbdkit-curl-plugin",
sha256 = "53412db6df5e098d2439d456a309e567af75b721178a9f7a5c10fa192ecf5d43",
urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/n/nbdkit-curl-plugin-1.22.3-2.fc33.x86_64.rpm",

],
)

http_file(
name = "libxcrypt-compat",
sha256 = "51d74854365a393393b4457e3d92ba103c08671b4c881a8a1d9fcb8a54a4a737",
Expand Down Expand Up @@ -581,8 +606,25 @@ http_file(
sha256 = "8c58134cdcec8a993c7da827abb4e9ab78d974038d984ff1fee39963d92736c5",
urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/g/golang-github-vmware-govmomi-0.23.1-1.fc33.x86_64.rpm",
"https://storage.googleapis.com/builddeps/8c58134cdcec8a993c7da827abb4e9ab78d974038d984ff1fee39963d92736c5",
],
],
)

http_file(
name = "libnbd",
sha256 = "a63602bb9ebc13f31543332164c64e9c5342089e7431fa35b393f0692b6acb97",

urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/l/libnbd-1.4.1-2.fc33.1.x86_64.rpm",

],
)

http_file(
name = "liburing",
sha256 = "049778a480dd02774934b37c127b345d8748bfbec1e584f9c412a41af34eaf89",
urls = [
"http://download.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/g/golang-github-vmware-govmomi-0.23.1-1.fc33.x86_64.rpm",
],
)

http_file(
Expand Down Expand Up @@ -611,3 +653,4 @@ http_file(
"https://storage.googleapis.com/builddeps/964e39835b59c76b7eb3f78c460bfc6e7acfb0c40b901775c7e8a7204537f8a7",
],
)

3 changes: 3 additions & 0 deletions cmd/cdi-importer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ rpm_image(
"@nbdkit-server//file",
"@nbdkit-basic-filters//file",
"@nbdkit-vddk-plugin//file",
"@nbdkit-curl-plugin//file",
"@nbdkit-xz-filter//file",
"@nbdkit-gzip-filter//file",
"@tar//file",
"@qemu-img//file",
"@qemu-block-curl//file",
Expand Down
2 changes: 2 additions & 0 deletions pkg/image/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"filefmt.go",
"nbdkit.go",
"qemu.go",
"validate.go",
],
Expand All @@ -25,6 +26,7 @@ go_test(
name = "go_default_test",
srcs = [
"filefmt_test.go",
"nbdkit_test.go",
"qemu_suite_test.go",
"qemu_test.go",
],
Expand Down
168 changes: 168 additions & 0 deletions pkg/image/nbdkit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package image

import (
"fmt"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/klog/v2"
"kubevirt.io/containerized-data-importer/pkg/system"
"net/url"
"strings"
)

var (
nbdkitExecFunction = system.ExecWithLimits
)

type nbdkitOperations struct {
nbdkit *Nbdkit
}

// NewNbdkitOperations return the implementation of nbdkit of QEMUOperations
func NewNbdkitOperations(n *Nbdkit) QEMUOperations {
return &nbdkitOperations{nbdkit: n}
}

// NbdkitPlugin represents a plugin for nbdkit
type NbdkitPlugin string

// NbdkitFilter represents s filter for nbdkit
type NbdkitFilter string

// Nbdkit plugins
const (
NbdkitCurlPlugin NbdkitPlugin = "curl"
)

// Nbdkit filters
const (
NbdkitXzFilter NbdkitFilter = "xz"
NbdkitTarFilter NbdkitFilter = "tar"
NbdkitGzipFilter NbdkitFilter = "gzip"
)

// Nbdkit represents struct for an nbdkit instance
type Nbdkit struct {
NbdPidFile string
nbdkitArgs []string
plugin NbdkitPlugin
pluginArgs []string
filters []NbdkitFilter
source *url.URL
}

// NewNbdkit creates a new Nbdkit instance with an nbdkit plugin and pid file
func NewNbdkit(plugin NbdkitPlugin, nbdkitPidFile string) *Nbdkit {
return &Nbdkit{
NbdPidFile: nbdkitPidFile,
plugin: plugin,
}
}

// NewNbdkitCurl creates a new Nbdkit instance with the curl plugin
func NewNbdkitCurl(nbdkitPidFile, certDir string) *Nbdkit {
var pluginArgs []string
args := []string{"-r"}
if certDir != "" {
pluginArgs = append(pluginArgs, fmt.Sprintf("cainfo=%s/%s", certDir, "tls.crt"))
}

return &Nbdkit{
NbdPidFile: nbdkitPidFile,
plugin: NbdkitCurlPlugin,
nbdkitArgs: args,
pluginArgs: pluginArgs,
}
}

// AddFilter adds a nbdkit filter if it doesn't already exist
func (n *Nbdkit) AddFilter(filter NbdkitFilter) {
for _, f := range n.filters {
if f == filter {
return
}
}
n.filters = append(n.filters, filter)
}

// Info returns the information about the content provided with the url
func (n *nbdkitOperations) Info(url *url.URL) (*ImgInfo, error) {
if len(url.Scheme) <= 0 {
return Info(url)
}
n.nbdkit.source = url
qemuImgArgs := []string{"--output=json"}
output, err := n.nbdkit.startNbdkitWithQemuImg("info", qemuImgArgs)
if err != nil {
return nil, errors.Errorf("%s, %s", output, err.Error())
}
return checkOutputQemuImgInfo(output, url.String())
}

// Validate validates the url
func (n *nbdkitOperations) Validate(url *url.URL, availableSize int64, filesystemOverhead float64) error {
info, err := n.Info(url)
if err != nil {
return err
}
return checkIfURLIsValid(info, availableSize, filesystemOverhead, url.String())
}

// ConvertToRawStream converts the content provided by the url to a raw disk in the dest
func (n *nbdkitOperations) ConvertToRawStream(url *url.URL, dest string, preallocate bool) error {
if len(url.Scheme) <= 0 {
return ConvertToRawStream(url, dest, preallocate)
}
n.nbdkit.source = url
qemuImgArgs := []string{"-p", "-O", "raw", dest, "-t", "none"}
if preallocate {
klog.V(1).Info("Added preallocation")
qemuImgArgs = append(qemuImgArgs, []string{"-o", "preallocation=falloc"}...)
}
_, err := n.nbdkit.startNbdkitWithQemuImg("convert", qemuImgArgs)
return err
}

// CreateBlankImage creates empty raw image
func (n *nbdkitOperations) CreateBlankImage(dest string, size resource.Quantity, preallocate bool) error {
// Use the default function to create an empty raw image
return CreateBlankImage(dest, size, preallocate)
}

func (n *nbdkitOperations) Resize(image string, size resource.Quantity) error {
return Resize(image, size)
}

func (n *Nbdkit) getSource() string {
var source string
switch n.plugin {
case NbdkitCurlPlugin:
source = fmt.Sprintf("url=%s", n.source.String())
default:
source = ""
}
return source
}

func (n *Nbdkit) startNbdkitWithQemuImg(qemuImgCmd string, qemuImgArgs []string) ([]byte, error) {
argsNbdkit := []string{
"--foreground",
"--readonly",
"-U", "-",
"--pidfile", n.NbdPidFile,
}
// set filters
for _, f := range n.filters {
argsNbdkit = append(argsNbdkit, fmt.Sprintf("--filter=%s", f))
}
// set additional arguments
for _, a := range n.nbdkitArgs {
argsNbdkit = append(argsNbdkit, a)
}
// append nbdkit plugin arguments
argsNbdkit = append(argsNbdkit, string(n.plugin), strings.Join(n.pluginArgs, " "), n.getSource())
// append qemu-img command
argsNbdkit = append(argsNbdkit, "--run", fmt.Sprintf("qemu-img %s $nbd %v", qemuImgCmd, strings.Join(qemuImgArgs, " ")))
klog.V(3).Infof("Start nbdkit with: %v", argsNbdkit)
return nbdkitExecFunction(nil, reportProgress, "nbdkit", argsNbdkit...)
}
Loading

0 comments on commit f33abe6

Please sign in to comment.