Skip to content

Commit

Permalink
feat(remote): init (#54)
Browse files Browse the repository at this point in the history
* feat(remote): init

* feat(python3/remote): init

* feat(cmd/remote): init

* chore: modify remote description

* feat(python3/remote): add remote mode

* fix: fix the wrong that remote runtime root is empty
  • Loading branch information
Tsuki124 authored Dec 14, 2022
1 parent d316ee9 commit 9e2a691
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 0 deletions.
59 changes: 59 additions & 0 deletions go/cmd/remote.go
Original file line number Diff line number Diff line change
@@ -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{})
}
50 changes: 50 additions & 0 deletions go/pkg/binding/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
53 changes: 53 additions & 0 deletions go/remote/image.go
Original file line number Diff line number Diff line change
@@ -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
}
17 changes: 17 additions & 0 deletions go/remote/option.go
Original file line number Diff line number Diff line change
@@ -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
}
}
68 changes: 68 additions & 0 deletions go/remote/remote.go
Original file line number Diff line number Diff line change
@@ -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()
}
10 changes: 10 additions & 0 deletions python3/veinmind/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
79 changes: 79 additions & 0 deletions python3/veinmind/remote.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 9e2a691

Please sign in to comment.