diff --git a/go/cmd/remote.go b/go/cmd/remote.go new file mode 100644 index 0000000..1716de8 --- /dev/null +++ b/go/cmd/remote.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "github.com/spf13/pflag" + + "github.com/chaitin/libveinmind/go/pkg/pflagext" + "github.com/chaitin/libveinmind/go/plugin" + "github.com/chaitin/libveinmind/go/remote" +) + +type remoteRoot struct { + runtime *remote.Runtime +} + +func (r remoteRoot) ID() interface{} { + return r.runtime +} + +func (r remoteRoot) Mode() string { + return "remote" +} + +func (r remoteRoot) Options() plugin.ExecOption { + return plugin.WithExecOptions(plugin.WithPrependArgs( + "--remote-root", r.runtime.Root())) +} + +var remoteRuntimeRoot string + +type remoteMode struct { +} + +func (remoteMode) Name() string { + return "remote" +} + +func (remoteMode) AddFlags(fset *pflag.FlagSet) { + pflagext.StringVarF(fset, func(root string) error { + remoteRuntimeRoot = root + return nil + }, "remote-root", + "remote manager system data root") +} + +func (remoteMode) Invoke(c *Command, args []string, m ModeHandler) error { + t, err := remote.New(remoteRuntimeRoot) + if err != nil { + return err + } + defer func() { _ = t.Close() }() + return m(c, args, t) +} + +func init() { + RegisterPartition(func(i *remote.Image) (Root, string) { + return remoteRoot{runtime: i.Runtime()}, i.ID() + }) + RegisterMode(&remoteMode{}) +} diff --git a/go/pkg/binding/functions.go b/go/pkg/binding/functions.go index bf5c468..3e2a01e 100644 --- a/go/pkg/binding/functions.go +++ b/go/pkg/binding/functions.go @@ -685,3 +685,53 @@ func (h Handle) TarballLayerId() string { defer result.Free() return result.String() } + +func RemoteNew(root string) (Handle, error) { + var result Handle + rootStr := NewString(root) + defer rootStr.Free() + if err := handleError(C.veinmind_RemoteNew(result.Ptr(), rootStr.ID())); err != nil { + return 0, err + } + return result, nil +} + +func (h Handle) RemoteLoad(imageRef, username, password string) ([]string, error) { + result := new(Handle) + imageRefStr := NewString(imageRef) + defer imageRefStr.Free() + + usernameStr := NewString(username) + defer usernameStr.Free() + + passwordStr := NewString(password) + defer passwordStr.Free() + + if err := handleError(C.veinmind_RemoteLoad(result.Ptr(), h.ID(), imageRefStr.ID(), usernameStr.ID(), passwordStr.ID())); err != nil { + return nil, err + } + defer result.Free() + return result.StringArray(), nil +} + +func (h Handle) RemoteImageOpenLayer(i int) (Handle, error) { + var result Handle + if err := handleError(C.veinmind_RemoteImageOpenLayer( + result.Ptr(), h.ID(), C.size_t(i))); err != nil { + return 0, err + } + return result, nil +} + +func (h Handle) RemoteImageNumLayers() int { + var numLayers C.size_t + assertNoError(C.veinmind_RemoteImageNumLayers(&numLayers, h.ID())) + return int(numLayers) +} + +func (h Handle) RemoteLayerId() string { + var result Handle + assertNoError(C.veinmind_RemoteLayerID(result.Ptr(), h.ID())) + defer result.Free() + return result.String() +} diff --git a/go/remote/image.go b/go/remote/image.go new file mode 100644 index 0000000..a545322 --- /dev/null +++ b/go/remote/image.go @@ -0,0 +1,53 @@ +package remote + +import ( + api "github.com/chaitin/libveinmind/go" + "github.com/chaitin/libveinmind/go/pkg/behaviour" + "github.com/chaitin/libveinmind/go/pkg/binding" +) + +// Image represents a remote image. +type Image struct { + behaviour.Closer + behaviour.Image + behaviour.FileSystem + image binding.Handle + runtime *Runtime +} + +type Layer struct { + behaviour.Closer + behaviour.FileSystem + layer binding.Handle + image *Image +} + +func (i *Image) Runtime() *Runtime { + return i.runtime +} + +func (i *Image) NumLayers() int { + return i.image.RemoteImageNumLayers() +} + +func (i *Image) OpenLayer(index int) (api.Layer, error) { + h, err := i.image.RemoteImageOpenLayer(index) + if err != nil { + return nil, err + } + + return &Layer{ + Closer: behaviour.NewCloser(&h), + FileSystem: behaviour.NewFileSystem(&h), + layer: h, + image: i, + }, nil +} + +func (l *Layer) ID() string { + return l.layer.RemoteLayerId() +} + +func (l *Layer) Image() *Image { + return l.image +} diff --git a/go/remote/option.go b/go/remote/option.go new file mode 100644 index 0000000..cf763a4 --- /dev/null +++ b/go/remote/option.go @@ -0,0 +1,17 @@ +package remote + +type loadOptions struct { + username string + password string +} + +// LoadOption is the option that can be used for loading an +// remote.Image object. +type LoadOption func(*loadOptions) + +func WithAuth(username, password string) LoadOption { + return func(o *loadOptions) { + o.username = username + o.password = password + } +} diff --git a/go/remote/remote.go b/go/remote/remote.go new file mode 100644 index 0000000..a23c4bb --- /dev/null +++ b/go/remote/remote.go @@ -0,0 +1,68 @@ +// Package remote is the API implementation on remote format image. +package remote + +import ( + "github.com/pkg/errors" + + api "github.com/chaitin/libveinmind/go" + "github.com/chaitin/libveinmind/go/pkg/behaviour" + "github.com/chaitin/libveinmind/go/pkg/binding" +) + +type Runtime struct { + root string + + behaviour.Closer + behaviour.Runtime + behaviour.FileSystem + runtime binding.Handle +} + +func New(root string) (api.Runtime, error) { + t := &Runtime{root: root} + + h, err := binding.RemoteNew(t.root) + if err != nil { + return nil, err + } + t.runtime = h + t.Closer = behaviour.NewCloser(&t.runtime) + t.Runtime = behaviour.NewRuntime(&t.runtime) + t.FileSystem = behaviour.NewFileSystem(&t.runtime) + + return t, nil +} + +func (t *Runtime) OpenImageByID(id string) (api.Image, error) { + h, err := t.runtime.RuntimeOpenImageByID(id) + if err != nil { + return nil, err + } + result := &Image{runtime: t, image: h} + result.Closer = behaviour.NewCloser(&result.image) + result.Image = behaviour.NewImage(&result.image) + result.FileSystem = behaviour.NewFileSystem(&result.image) + return result, nil +} + +func (t *Runtime) OpenContainerByID(id string) (api.Container, error) { + return nil, errors.New("remote: unsupported") +} + +// Root return data root for remote system +func (t *Runtime) Root() string { + return t.root +} + +// Load image into remote manager system +func (t *Runtime) Load(imageRef string, opts ...LoadOption) ([]string, error) { + options := &loadOptions{} + for _, o := range opts { + o(options) + } + return t.runtime.RemoteLoad(imageRef, options.username, options.password) +} + +func (t *Runtime) Close() error { + return t.runtime.Close() +} diff --git a/python3/veinmind/command.py b/python3/veinmind/command.py index 07faf1f..a1b88e3 100644 --- a/python3/veinmind/command.py +++ b/python3/veinmind/command.py @@ -263,6 +263,16 @@ def _tarball_mode(callback, **kwargs): ) as t: callback(t) +@mode(name="remote") +@decorators.option("--remote-root", + help='flag "--remote-root" of remote command') +def _remote_mode(callback, **kwargs): + from . import remote + with remote.Runtime( + root=kwargs.pop("remote_root", None), + ) as t: + callback(t) + class ModeCommand(PluginCommand): """ModeCommand is the command that will accept in a mode flag diff --git a/python3/veinmind/remote.py b/python3/veinmind/remote.py new file mode 100644 index 0000000..cf5c304 --- /dev/null +++ b/python3/veinmind/remote.py @@ -0,0 +1,79 @@ +from . import binding as binding +from . import runtime as runtime +from . import image as image +from . import filesystem as filesystem +import ctypes as C + + +class Remote(runtime.Runtime): + _new = binding.lookup(b"veinmind_RemoteNew", b"VEINMIND_1.4") + + def __init__(self, root): + with binding.new_str(root) as hstr: + handle = binding.Handle() + binding.handle_error(Remote._new( + handle.ptr(), hstr.val())) + super(Remote, self).__init__(handle=handle) + + _open_image_by_id = binding.lookup( + b"veinmind_RuntimeOpenImageByID", b"VEINMIND_1.0") + + def open_image_by_id(self, image_id): + with binding.new_str(image_id) as hstr: + handle = binding.Handle() + binding.handle_error(Remote._open_image_by_id( + handle.ptr(), self.__handle__().val(), hstr.val())) + return Image(handle) + + _load = binding.lookup( + b"veinmind_RemoteLoad", b"VEINMIND_1.4") + + def load(self, image_ref,username,password): + with binding.Handle() as handle: + with binding.new_str(path) as hstr: + with binding.new_str(username) as ustr + with binding.new_str(password) as pstr + binding.handle_error(Remote._load( + handle.ptr(), self.__handle__().val(), hstr.val(),ustr.val(),pstr.val())) + return handle.str_list() + + +class Layer(filesystem.FileSystem): + "Layer refers to a layer in docker image." + + # Initialize the docker layer object. + def __init__(self, handle): + super(Layer, self).__init__(handle=handle) + + _id = binding.lookup(b"veinmind_RemoteLayerID", b"VEINMIND_1.4") + + def id(self): + "Retrieve the diff ID of the docker layer." + + handle = binding.Handle() + binding.handle_error(Layer._id( + handle.ptr(), self.__handle__().val())) + with handle as handle: + return handle.str() + + +class Image(image.Image): + _open_layer = binding.lookup( + b"veinmind_RemoteImageOpenLayer", b"VEINMIND_1.4") + def open_layer(self, i): + "Open specified layer in the docker image." + + handle = binding.Handle() + binding.handle_error(Image._open_layer( + handle.ptr(), self.__handle__().val(), C.c_size_t(i))) + return Layer(handle) + + _num_layers = binding.lookup( + b"veinmind_RemoteImageNumLayers", b"VEINMIND_1.4") + def num_layers(self): + "Return the number of layers in the tarball image." + + result = C.c_size_t() + binding.handle_error(Image._num_layers( + C.pointer(result), self.__handle__().val())) + return result.value \ No newline at end of file