containerized-data-importer/tools/cdi-containerimage-server/main.go
Arnon Gilboa addf25b4f9
Support registry import using node docker cache (#1913)
* Support registry import using node docker cache

The new CRI (container runtime interface) importer pod is created with three containers and a shared emptyDir volume:
-Init container: copies static http server binary to empty dir
-Server container: container image container configured to run the http binary and serve up the image file in /data
-Client container: import.sh uses cdi-import to import from server container, and writes "done" file on emptydir
-Server container sees "done" file and exits

Thanks mhenriks for the PoC!

Done:
-added ImportMethod to DataVolumeSourceRegistry (DataVolume.Spec.Source.Registry, DataImportCron.Spec.Source.Registry).
Import method can be "skopeo" (default), or "cri" for container runtime interface based import
-added cdi-containerimage-server & import.sh to the cdi-importer container

ToDo:
-utests and func tests
-doc

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add tests, fix CR comments

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* CR fixes

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Use deployment docker prefix and tag in func tests

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add OpenShift ImageStreams import support

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add importer pod lookup annotation for image streams

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add pullMethod and imageStream doc

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2021-09-20 22:05:36 +02:00

94 lines
2.2 KiB
Go
Executable File

package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
)
func printFiles(dir string) error {
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
fmt.Println(path)
return nil
})
}
func renameImageFile(dir, newName string) error {
entries, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
if len(entries) != 1 || entries[0].IsDir() {
return errors.Errorf("Invalid container image")
}
src := filepath.Join(dir, entries[0].Name())
target := filepath.Join(dir, newName)
if err := os.Rename(src, target); err != nil {
return err
}
return nil
}
func main() {
port := flag.Int("p", 8100, "server port")
directory := flag.String("image-dir", ".", "directory to serve")
readyFile := flag.String("ready-file", "/shared/ready", "file to create when ready for connections")
doneFile := flag.String("done-file", "/shared/done", "file created when the client is done")
imageName := flag.String("image-name", "disk.img", "name of the image to serve up")
flag.Parse()
if err := printFiles(*directory); err != nil {
log.Fatalf("Failed walking the directory %s: %v", *directory, err)
}
if err := renameImageFile(*directory, *imageName); err != nil {
log.Fatalf("Failed renaming image file %s, directory %s: %v", *imageName, *directory, err)
}
server := &http.Server{
Handler: http.FileServer(http.Dir(*directory)),
}
addr := fmt.Sprintf("localhost:%d", *port)
listener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("Failed listening on %s err: %v", addr, err)
}
f, err := os.OpenFile(*readyFile, os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
log.Fatalf("Failed creating \"ready\" file: %v", err)
}
defer os.Remove(*readyFile)
f.Close()
go func() {
log.Printf("Serving %s on HTTP port: %d\n", *directory, *port)
if err := server.Serve(listener); err != nil && err != http.ErrServerClosed {
log.Fatalf("Serve failed: %v", err)
}
}()
for {
if _, err := os.Stat(*doneFile); err == nil {
break
}
time.Sleep(time.Second)
}
os.Remove(*doneFile)
if err := server.Shutdown(context.TODO()); err != nil {
log.Printf("Shutdown failed: %v\n", err)
}
log.Println("Importer has completed")
}