mirror of
https://github.com/containers/podman.git
synced 2025-06-25 03:52:15 +08:00
Merge pull request #2227 from baude/remoteexport
podman-remote import|export
This commit is contained in:
@ -12,8 +12,6 @@ func getAppCommands() []cli.Command {
|
|||||||
createCommand,
|
createCommand,
|
||||||
diffCommand,
|
diffCommand,
|
||||||
execCommand,
|
execCommand,
|
||||||
exportCommand,
|
|
||||||
importCommand,
|
|
||||||
killCommand,
|
killCommand,
|
||||||
kubeCommand,
|
kubeCommand,
|
||||||
loadCommand,
|
loadCommand,
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
containerSubCommands = []cli.Command{
|
containerSubCommands = []cli.Command{
|
||||||
|
exportCommand,
|
||||||
inspectCommand,
|
inspectCommand,
|
||||||
}
|
}
|
||||||
containerDescription = "Manage containers"
|
containerDescription = "Manage containers"
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
"github.com/containers/libpod/libpod/adapter"
|
||||||
"github.com/containers/libpod/libpod"
|
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -43,7 +40,7 @@ func exportCmd(c *cli.Context) error {
|
|||||||
rootless.SetSkipStorageSetup(true)
|
rootless.SetSkipStorageSetup(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime, err := libpodruntime.GetRuntime(c)
|
runtime, err := adapter.GetRuntime(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not get runtime")
|
return errors.Wrapf(err, "could not get runtime")
|
||||||
}
|
}
|
||||||
@ -58,52 +55,18 @@ func exportCmd(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := c.String("output")
|
output := c.String("output")
|
||||||
|
if runtime.Remote && (output == "/dev/stdout" || len(output) == 0) {
|
||||||
|
return errors.New("remote client usage must specify an output file (-o)")
|
||||||
|
}
|
||||||
if output == "/dev/stdout" {
|
if output == "/dev/stdout" {
|
||||||
file := os.Stdout
|
file := os.Stdout
|
||||||
if logrus.IsTerminal(file) {
|
if logrus.IsTerminal(file) {
|
||||||
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
|
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateFileName(output); err != nil {
|
if err := validateFileName(output); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return runtime.Export(args[0], c.String("output"))
|
||||||
ctr, err := runtime.LookupContainer(args[0])
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error looking up container %q", args[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.Geteuid() != 0 {
|
|
||||||
state, err := ctr.State()
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
|
|
||||||
}
|
|
||||||
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
|
|
||||||
data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
|
|
||||||
}
|
|
||||||
conmonPid, err := strconv.Atoi(string(data))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "cannot parse PID %q", data)
|
|
||||||
}
|
|
||||||
became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if became {
|
|
||||||
os.Exit(ret)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
became, ret, err := rootless.BecomeRootInUserNS()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if became {
|
|
||||||
os.Exit(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctr.Export(output)
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
imageSubCommands = []cli.Command{
|
imageSubCommands = []cli.Command{
|
||||||
|
importCommand,
|
||||||
historyCommand,
|
historyCommand,
|
||||||
imageExistsCommand,
|
imageExistsCommand,
|
||||||
inspectCommand,
|
inspectCommand,
|
||||||
|
@ -2,16 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
"github.com/containers/libpod/libpod/adapter"
|
||||||
"github.com/containers/libpod/libpod/image"
|
|
||||||
"github.com/containers/libpod/pkg/util"
|
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
@ -51,7 +43,7 @@ func importCmd(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime, err := libpodruntime.GetRuntime(c)
|
runtime, err := adapter.GetRuntime(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not get runtime")
|
return errors.Wrapf(err, "could not get runtime")
|
||||||
}
|
}
|
||||||
@ -60,7 +52,6 @@ func importCmd(c *cli.Context) error {
|
|||||||
var (
|
var (
|
||||||
source string
|
source string
|
||||||
reference string
|
reference string
|
||||||
writer io.Writer
|
|
||||||
)
|
)
|
||||||
|
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
@ -80,67 +71,13 @@ func importCmd(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
changes := v1.ImageConfig{}
|
quiet := c.Bool("quiet")
|
||||||
if c.IsSet("change") || c.IsSet("c") {
|
if runtime.Remote {
|
||||||
changes, err = util.GetImageConfig(c.StringSlice("change"))
|
quiet = false
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error adding config changes to image %q", source)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
iid, err := runtime.Import(getContext(), source, reference, c.StringSlice("change"), c.String("message"), quiet)
|
||||||
history := []v1.History{
|
|
||||||
{Comment: c.String("message")},
|
|
||||||
}
|
|
||||||
|
|
||||||
config := v1.Image{
|
|
||||||
Config: changes,
|
|
||||||
History: history,
|
|
||||||
}
|
|
||||||
|
|
||||||
writer = nil
|
|
||||||
if !c.Bool("quiet") {
|
|
||||||
writer = os.Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
// if source is a url, download it and save to a temp file
|
|
||||||
u, err := url.ParseRequestURI(source)
|
|
||||||
if err == nil && u.Scheme != "" {
|
|
||||||
file, err := downloadFromURL(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer os.Remove(file)
|
|
||||||
source = file
|
|
||||||
}
|
|
||||||
|
|
||||||
newImage, err := runtime.ImageRuntime().Import(getContext(), source, reference, writer, image.SigningOptions{}, config)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println(newImage.ID())
|
fmt.Println(iid)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
|
|
||||||
// and temporarily saves in it /var/tmp/importxyz, which is deleted after the image is imported
|
|
||||||
func downloadFromURL(source string) (string, error) {
|
|
||||||
fmt.Printf("Downloading from %q\n", source)
|
|
||||||
|
|
||||||
outFile, err := ioutil.TempFile("/var/tmp", "import")
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "error creating file")
|
|
||||||
}
|
|
||||||
defer outFile.Close()
|
|
||||||
|
|
||||||
response, err := http.Get(source)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrapf(err, "error downloading %q", source)
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(outFile, response.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
return outFile.Name(), nil
|
|
||||||
}
|
|
||||||
|
@ -88,9 +88,11 @@ func main() {
|
|||||||
|
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
containerCommand,
|
containerCommand,
|
||||||
|
exportCommand,
|
||||||
historyCommand,
|
historyCommand,
|
||||||
imageCommand,
|
imageCommand,
|
||||||
imagesCommand,
|
imagesCommand,
|
||||||
|
importCommand,
|
||||||
infoCommand,
|
infoCommand,
|
||||||
inspectCommand,
|
inspectCommand,
|
||||||
pullCommand,
|
pullCommand,
|
||||||
|
@ -688,7 +688,7 @@ method Commit(name: string, image_name: string, changes: []string, author: strin
|
|||||||
|
|
||||||
# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
|
# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
|
||||||
# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
|
# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
|
||||||
method ImportImage(source: string, reference: string, message: string, changes: []string) -> (image: string)
|
method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string)
|
||||||
|
|
||||||
# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also
|
# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also
|
||||||
# a booleon option to force compression. It also takes in a string array of tags to be able to save multiple
|
# a booleon option to force compression. It also takes in a string array of tags to be able to save multiple
|
||||||
@ -1050,6 +1050,9 @@ method ContainerInspectData(name: string) -> (config: string)
|
|||||||
# development of Podman only and generally should not be used.
|
# development of Podman only and generally should not be used.
|
||||||
method ContainerStateData(name: string) -> (config: string)
|
method ContainerStateData(name: string) -> (config: string)
|
||||||
|
|
||||||
|
method SendFile(type: string, length: int) -> (file_handle: string)
|
||||||
|
method ReceiveFile(path: string, delete: bool) -> (len: int)
|
||||||
|
|
||||||
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
|
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
|
||||||
error ImageNotFound (name: string)
|
error ImageNotFound (name: string)
|
||||||
|
|
||||||
|
@ -34,3 +34,14 @@ func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
|
|||||||
}
|
}
|
||||||
return connection, nil
|
return connection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RefreshConnection is used to replace the current r.Conn after things like
|
||||||
|
// using an upgraded varlink connection
|
||||||
|
func (r RemoteRuntime) RefreshConnection() error {
|
||||||
|
newConn, err := r.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Conn = newConn
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -4,12 +4,17 @@ package adapter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/containers/image/types"
|
"github.com/containers/image/types"
|
||||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/libpod/image"
|
"github.com/containers/libpod/libpod/image"
|
||||||
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -104,3 +109,49 @@ func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
|
|||||||
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
|
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
|
||||||
return r.ImageRuntime().PruneImages(all)
|
return r.ImageRuntime().PruneImages(all)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export is a wrapper to container export to a tarfile
|
||||||
|
func (r *LocalRuntime) Export(name string, path string) error {
|
||||||
|
ctr, err := r.Runtime.LookupContainer(name)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error looking up container %q", name)
|
||||||
|
}
|
||||||
|
if os.Geteuid() != 0 {
|
||||||
|
state, err := ctr.State()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
|
||||||
|
}
|
||||||
|
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
|
||||||
|
data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
|
||||||
|
}
|
||||||
|
conmonPid, err := strconv.Atoi(string(data))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot parse PID %q", data)
|
||||||
|
}
|
||||||
|
became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if became {
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
became, ret, err := rootless.BecomeRootInUserNS()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if became {
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctr.Export(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import is a wrapper to import a container image
|
||||||
|
func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
|
||||||
|
return r.Runtime.Import(ctx, source, reference, changes, history, quiet)
|
||||||
|
}
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
package adapter
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -324,6 +326,84 @@ func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
|
|||||||
return &data
|
return &data
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PruneImages is the wrapper call for a remote-client to prune images
|
||||||
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
|
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
|
||||||
return iopodman.ImagesPrune().Call(r.Conn, all)
|
return iopodman.ImagesPrune().Call(r.Conn, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export is a wrapper to container export to a tarfile
|
||||||
|
func (r *LocalRuntime) Export(name string, path string) error {
|
||||||
|
tempPath, err := iopodman.ExportContainer().Call(r.Conn, name, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outputFile.Close()
|
||||||
|
|
||||||
|
writer := bufio.NewWriter(outputFile)
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
reply, err := iopodman.ReceiveFile().Send(r.Conn, varlink.Upgrade, tempPath, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
length, _, err := reply()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "unable to get file length for transfer")
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := r.Conn.Reader
|
||||||
|
if _, err := io.CopyN(writer, reader, length); err != nil {
|
||||||
|
return errors.Wrap(err, "file transer failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import implements the remote calls required to import a container image to the store
|
||||||
|
func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
|
||||||
|
// First we send the file to the host
|
||||||
|
fs, err := os.Open(source)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo, err := fs.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
reply, err := iopodman.SendFile().Send(r.Conn, varlink.Upgrade, "", int64(fileInfo.Size()))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, _, err = reply()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(fs)
|
||||||
|
_, err = reader.WriteTo(r.Conn.Writer)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
r.Conn.Writer.Flush()
|
||||||
|
|
||||||
|
// All was sent, wait for the ACK from the server
|
||||||
|
tempFile, err := r.Conn.Reader.ReadString(':')
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// r.Conn is kaput at this point due to the upgrade
|
||||||
|
if err := r.RemoteRuntime.RefreshConnection(); err != nil {
|
||||||
|
return "", err
|
||||||
|
|
||||||
|
}
|
||||||
|
return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true)
|
||||||
|
}
|
||||||
|
@ -2,9 +2,11 @@ package libpod
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -521,3 +523,44 @@ func isNamedVolume(volName string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export is the libpod portion of exporting a container to a tar file
|
||||||
|
func (r *Runtime) Export(name string, path string) error {
|
||||||
|
ctr, err := r.LookupContainer(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if os.Geteuid() != 0 {
|
||||||
|
state, err := ctr.State()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
|
||||||
|
}
|
||||||
|
if state == ContainerStateRunning || state == ContainerStatePaused {
|
||||||
|
data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
|
||||||
|
}
|
||||||
|
conmonPid, err := strconv.Atoi(string(data))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot parse PID %q", data)
|
||||||
|
}
|
||||||
|
became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if became {
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
became, ret, err := rootless.BecomeRootInUserNS()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if became {
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctr.Export(path)
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -3,9 +3,16 @@ package libpod
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/containers/buildah/imagebuildah"
|
"github.com/containers/buildah/imagebuildah"
|
||||||
"github.com/containers/libpod/libpod/image"
|
"github.com/containers/libpod/libpod/image"
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -132,3 +139,75 @@ func (r *Runtime) Build(ctx context.Context, options imagebuildah.BuildOptions,
|
|||||||
_, _, err := imagebuildah.BuildDockerfiles(ctx, r.store, options, dockerfiles...)
|
_, _, err := imagebuildah.BuildDockerfiles(ctx, r.store, options, dockerfiles...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import is called as an intermediary to the image library Import
|
||||||
|
func (r *Runtime) Import(ctx context.Context, source string, reference string, changes []string, history string, quiet bool) (string, error) {
|
||||||
|
var (
|
||||||
|
writer io.Writer
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
ic := v1.ImageConfig{}
|
||||||
|
if len(changes) > 0 {
|
||||||
|
ic, err = util.GetImageConfig(changes)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "error adding config changes to image %q", source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hist := []v1.History{
|
||||||
|
{Comment: history},
|
||||||
|
}
|
||||||
|
|
||||||
|
config := v1.Image{
|
||||||
|
Config: ic,
|
||||||
|
History: hist,
|
||||||
|
}
|
||||||
|
|
||||||
|
writer = nil
|
||||||
|
if !quiet {
|
||||||
|
writer = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
// if source is a url, download it and save to a temp file
|
||||||
|
u, err := url.ParseRequestURI(source)
|
||||||
|
if err == nil && u.Scheme != "" {
|
||||||
|
file, err := downloadFromURL(source)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer os.Remove(file)
|
||||||
|
source = file
|
||||||
|
}
|
||||||
|
|
||||||
|
newImage, err := r.imageRuntime.Import(ctx, source, reference, writer, image.SigningOptions{}, config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return newImage.ID(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
|
||||||
|
// and temporarily saves in it /var/tmp/importxyz, which is deleted after the image is imported
|
||||||
|
func downloadFromURL(source string) (string, error) {
|
||||||
|
fmt.Printf("Downloading from %q\n", source)
|
||||||
|
|
||||||
|
outFile, err := ioutil.TempFile("/var/tmp", "import")
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "error creating file")
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
response, err := http.Get(source)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "error downloading %q", source)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(outFile, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
return outFile.Name(), nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -194,15 +195,25 @@ func (i *LibpodAPI) ListContainerChanges(call iopodman.VarlinkCall, name string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExportContainer ...
|
// ExportContainer ...
|
||||||
func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, path string) error {
|
func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error {
|
||||||
ctr, err := i.Runtime.LookupContainer(name)
|
ctr, err := i.Runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyContainerNotFound(name)
|
return call.ReplyContainerNotFound(name)
|
||||||
}
|
}
|
||||||
if err := ctr.Export(path); err != nil {
|
outputFile, err := ioutil.TempFile("", "varlink_recv")
|
||||||
|
if err != nil {
|
||||||
return call.ReplyErrorOccurred(err.Error())
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
}
|
}
|
||||||
return call.ReplyExportContainer(path)
|
|
||||||
|
defer outputFile.Close()
|
||||||
|
if outPath == "" {
|
||||||
|
outPath = outputFile.Name()
|
||||||
|
}
|
||||||
|
if err := ctr.Export(outPath); err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
return call.ReplyExportContainer(outPath)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerStats ...
|
// GetContainerStats ...
|
||||||
|
@ -500,7 +500,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ImportImage imports an image from a tarball to the image store
|
// ImportImage imports an image from a tarball to the image store
|
||||||
func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string) error {
|
func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error {
|
||||||
configChanges, err := util.GetImageConfig(changes)
|
configChanges, err := util.GetImageConfig(changes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyErrorOccurred(err.Error())
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
@ -516,6 +516,12 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyErrorOccurred(err.Error())
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
}
|
}
|
||||||
|
if delete {
|
||||||
|
if err := os.Remove(source); err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return call.ReplyImportImage(newImage.ID())
|
return call.ReplyImportImage(newImage.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
75
pkg/varlinkapi/transfers.go
Normal file
75
pkg/varlinkapi/transfers.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package varlinkapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/cmd/podman/varlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendFile allows a client to send a file to the varlink server
|
||||||
|
func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int64) error {
|
||||||
|
if !call.WantsUpgrade() {
|
||||||
|
return call.ReplyErrorOccurred("client must use upgraded connection to send files")
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile, err := ioutil.TempFile("", "varlink_send")
|
||||||
|
if err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
defer outputFile.Close()
|
||||||
|
|
||||||
|
if err = call.ReplySendFile(outputFile.Name()); err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
writer := bufio.NewWriter(outputFile)
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
reader := call.Call.Reader
|
||||||
|
if _, err := io.CopyN(writer, reader, length); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an ACK to the client
|
||||||
|
call.Call.Writer.WriteString(fmt.Sprintf("%s:", outputFile.Name()))
|
||||||
|
call.Call.Writer.Flush()
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReceiveFile allows the varlink server to send a file to a client
|
||||||
|
func (i *LibpodAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, delete bool) error {
|
||||||
|
if !call.WantsUpgrade() {
|
||||||
|
return call.ReplyErrorOccurred("client must use upgraded connection to send files")
|
||||||
|
}
|
||||||
|
fs, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
fileInfo, err := fs.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the file length down to client
|
||||||
|
// Varlink connection upraded
|
||||||
|
if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(fs)
|
||||||
|
_, err = reader.WriteTo(call.Writer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if delete {
|
||||||
|
if err := os.Remove(filepath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return call.Writer.Flush()
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
// +build !remoteclient
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -37,6 +35,7 @@ var _ = Describe("Podman export", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("podman export output flag", func() {
|
It("podman export output flag", func() {
|
||||||
|
SkipIfRemote()
|
||||||
_, ec, cid := podmanTest.RunLsContainer("")
|
_, ec, cid := podmanTest.RunLsContainer("")
|
||||||
Expect(ec).To(Equal(0))
|
Expect(ec).To(Equal(0))
|
||||||
|
|
||||||
|
21
vendor/github.com/varlink/go/varlink/bridge.go
generated
vendored
21
vendor/github.com/varlink/go/varlink/bridge.go
generated
vendored
@ -5,13 +5,13 @@ package varlink
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PipeCon struct {
|
type PipeCon struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
|
cmd *exec.Cmd
|
||||||
reader *io.ReadCloser
|
reader *io.ReadCloser
|
||||||
writer *io.WriteCloser
|
writer *io.WriteCloser
|
||||||
}
|
}
|
||||||
@ -25,6 +25,8 @@ func (p PipeCon) Close() error {
|
|||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
p.cmd.Wait()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,18 +44,15 @@ func NewBridge(bridge string) (*Connection, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.conn = PipeCon{nil, &r, &w}
|
c.conn = PipeCon{nil, cmd, &r, &w}
|
||||||
c.address = ""
|
c.address = ""
|
||||||
c.reader = bufio.NewReader(r)
|
c.Reader = bufio.NewReader(r)
|
||||||
c.writer = bufio.NewWriter(w)
|
c.Writer = bufio.NewWriter(w)
|
||||||
|
|
||||||
go func() {
|
err = cmd.Start()
|
||||||
err := cmd.Run()
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
vendor/github.com/varlink/go/varlink/bridge_windows.go
generated
vendored
17
vendor/github.com/varlink/go/varlink/bridge_windows.go
generated
vendored
@ -3,13 +3,13 @@ package varlink
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PipeCon struct {
|
type PipeCon struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
|
cmd *exec.Cmd
|
||||||
reader *io.ReadCloser
|
reader *io.ReadCloser
|
||||||
writer *io.WriteCloser
|
writer *io.WriteCloser
|
||||||
}
|
}
|
||||||
@ -23,6 +23,8 @@ func (p PipeCon) Close() error {
|
|||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
p.cmd.Wait()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,18 +42,15 @@ func NewBridge(bridge string) (*Connection, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.conn = PipeCon{nil, &r, &w}
|
c.conn = PipeCon{nil, cmd, &r, &w}
|
||||||
c.address = ""
|
c.address = ""
|
||||||
c.reader = bufio.NewReader(r)
|
c.reader = bufio.NewReader(r)
|
||||||
c.writer = bufio.NewWriter(w)
|
c.writer = bufio.NewWriter(w)
|
||||||
|
|
||||||
go func() {
|
err = cmd.Start()
|
||||||
err := cmd.Run()
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
vendor/github.com/varlink/go/varlink/call.go
generated
vendored
21
vendor/github.com/varlink/go/varlink/call.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,9 +12,11 @@ import (
|
|||||||
// client can be terminated by returning an error from the call instead
|
// client can be terminated by returning an error from the call instead
|
||||||
// of sending a reply or error reply.
|
// of sending a reply or error reply.
|
||||||
type Call struct {
|
type Call struct {
|
||||||
writer *bufio.Writer
|
*bufio.Reader
|
||||||
|
*bufio.Writer
|
||||||
in *serviceCall
|
in *serviceCall
|
||||||
Continues bool
|
Continues bool
|
||||||
|
Upgrade bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// WantsMore indicates if the calling client accepts more than one reply to this method call.
|
// WantsMore indicates if the calling client accepts more than one reply to this method call.
|
||||||
@ -21,6 +24,11 @@ func (c *Call) WantsMore() bool {
|
|||||||
return c.in.More
|
return c.in.More
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WantsUpgrade indicates that the calling client wants the connection to be upgraded.
|
||||||
|
func (c *Call) WantsUpgrade() bool {
|
||||||
|
return c.in.Upgrade
|
||||||
|
}
|
||||||
|
|
||||||
// IsOneway indicate that the calling client does not expect a reply.
|
// IsOneway indicate that the calling client does not expect a reply.
|
||||||
func (c *Call) IsOneway() bool {
|
func (c *Call) IsOneway() bool {
|
||||||
return c.in.Oneway
|
return c.in.Oneway
|
||||||
@ -45,11 +53,18 @@ func (c *Call) sendMessage(r *serviceReply) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b = append(b, 0)
|
b = append(b, 0)
|
||||||
_, e = c.writer.Write(b)
|
_, e = c.Writer.Write(b)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
if e == io.EOF {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return c.writer.Flush()
|
e = c.Writer.Flush()
|
||||||
|
if e == io.EOF {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reply sends a reply to this method call.
|
// Reply sends a reply to this method call.
|
||||||
|
84
vendor/github.com/varlink/go/varlink/connection.go
generated
vendored
84
vendor/github.com/varlink/go/varlink/connection.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -15,15 +16,59 @@ const (
|
|||||||
More = 1 << iota
|
More = 1 << iota
|
||||||
Oneway = 1 << iota
|
Oneway = 1 << iota
|
||||||
Continues = 1 << iota
|
Continues = 1 << iota
|
||||||
|
Upgrade = 1 << iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error is a varlink error returned from a method call.
|
// Error is a varlink error returned from a method call.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
error
|
|
||||||
Name string
|
Name string
|
||||||
Parameters interface{}
|
Parameters interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Error) DispatchError() error {
|
||||||
|
errorRawParameters := e.Parameters.(*json.RawMessage)
|
||||||
|
|
||||||
|
switch e.Name {
|
||||||
|
case "org.varlink.service.InterfaceNotFound":
|
||||||
|
var param InterfaceNotFound
|
||||||
|
if errorRawParameters != nil {
|
||||||
|
err := json.Unmarshal(*errorRawParameters, ¶m)
|
||||||
|
if err != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ¶m
|
||||||
|
case "org.varlink.service.MethodNotFound":
|
||||||
|
var param MethodNotFound
|
||||||
|
if errorRawParameters != nil {
|
||||||
|
err := json.Unmarshal(*errorRawParameters, ¶m)
|
||||||
|
if err != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ¶m
|
||||||
|
case "org.varlink.service.MethodNotImplemented":
|
||||||
|
var param MethodNotImplemented
|
||||||
|
if errorRawParameters != nil {
|
||||||
|
err := json.Unmarshal(*errorRawParameters, ¶m)
|
||||||
|
if err != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ¶m
|
||||||
|
case "org.varlink.service.InvalidParameter":
|
||||||
|
var param InvalidParameter
|
||||||
|
if errorRawParameters != nil {
|
||||||
|
err := json.Unmarshal(*errorRawParameters, ¶m)
|
||||||
|
if err != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ¶m
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
// Error returns the fully-qualified varlink error name.
|
// Error returns the fully-qualified varlink error name.
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
return e.Name
|
return e.Name
|
||||||
@ -31,10 +76,11 @@ func (e *Error) Error() string {
|
|||||||
|
|
||||||
// Connection is a connection from a client to a service.
|
// Connection is a connection from a client to a service.
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
|
io.Closer
|
||||||
address string
|
address string
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
reader *bufio.Reader
|
Reader *bufio.Reader
|
||||||
writer *bufio.Writer
|
Writer *bufio.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send sends a method call. It returns a receive() function which is called to retrieve the method reply.
|
// Send sends a method call. It returns a receive() function which is called to retrieve the method reply.
|
||||||
@ -46,6 +92,7 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
|
|||||||
Parameters interface{} `json:"parameters,omitempty"`
|
Parameters interface{} `json:"parameters,omitempty"`
|
||||||
More bool `json:"more,omitempty"`
|
More bool `json:"more,omitempty"`
|
||||||
Oneway bool `json:"oneway,omitempty"`
|
Oneway bool `json:"oneway,omitempty"`
|
||||||
|
Upgrade bool `json:"upgrade,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags&More != 0) && (flags&Oneway != 0) {
|
if (flags&More != 0) && (flags&Oneway != 0) {
|
||||||
@ -55,11 +102,19 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags&More != 0) && (flags&Upgrade != 0) {
|
||||||
|
return nil, &Error{
|
||||||
|
Name: "org.varlink.InvalidParameter",
|
||||||
|
Parameters: "more",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m := call{
|
m := call{
|
||||||
Method: method,
|
Method: method,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
More: flags&More != 0,
|
More: flags&More != 0,
|
||||||
Oneway: flags&Oneway != 0,
|
Oneway: flags&Oneway != 0,
|
||||||
|
Upgrade: flags&Upgrade != 0,
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(m)
|
b, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -67,13 +122,19 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
b = append(b, 0)
|
b = append(b, 0)
|
||||||
_, err = c.writer.Write(b)
|
_, err = c.Writer.Write(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.writer.Flush()
|
err = c.Writer.Flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +145,11 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
|
|||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := c.reader.ReadBytes('\x00')
|
out, err := c.Reader.ReadBytes('\x00')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,11 +160,11 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.Error != "" {
|
if m.Error != "" {
|
||||||
err = &Error{
|
e := &Error{
|
||||||
Name: m.Error,
|
Name: m.Error,
|
||||||
Parameters: m.Parameters,
|
Parameters: m.Parameters,
|
||||||
}
|
}
|
||||||
return 0, err
|
return 0, e.DispatchError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Parameters != nil {
|
if m.Parameters != nil {
|
||||||
@ -220,8 +284,8 @@ func NewConnection(address string) (*Connection, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.address = address
|
c.address = address
|
||||||
c.reader = bufio.NewReader(c.conn)
|
c.Reader = bufio.NewReader(c.conn)
|
||||||
c.writer = bufio.NewWriter(c.conn)
|
c.Writer = bufio.NewWriter(c.conn)
|
||||||
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
53
vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
generated
vendored
53
vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
generated
vendored
@ -1,5 +1,42 @@
|
|||||||
package varlink
|
package varlink
|
||||||
|
|
||||||
|
// The requested interface was not found.
|
||||||
|
type InterfaceNotFound struct {
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e InterfaceNotFound) Error() string {
|
||||||
|
return "org.varlink.service.InterfaceNotFound"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The requested method was not found
|
||||||
|
type MethodNotFound struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MethodNotFound) Error() string {
|
||||||
|
return "org.varlink.service.MethodNotFound"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The interface defines the requested method, but the service does not
|
||||||
|
// implement it.
|
||||||
|
type MethodNotImplemented struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MethodNotImplemented) Error() string {
|
||||||
|
return "org.varlink.service.MethodNotImplemented"
|
||||||
|
}
|
||||||
|
|
||||||
|
// One of the passed parameters is invalid.
|
||||||
|
type InvalidParameter struct {
|
||||||
|
Parameter string `json:"parameter"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e InvalidParameter) Error() string {
|
||||||
|
return "org.varlink.service.InvalidParameter"
|
||||||
|
}
|
||||||
|
|
||||||
func doReplyError(c *Call, name string, parameters interface{}) error {
|
func doReplyError(c *Call, name string, parameters interface{}) error {
|
||||||
return c.sendMessage(&serviceReply{
|
return c.sendMessage(&serviceReply{
|
||||||
Error: name,
|
Error: name,
|
||||||
@ -9,36 +46,28 @@ func doReplyError(c *Call, name string, parameters interface{}) error {
|
|||||||
|
|
||||||
// ReplyInterfaceNotFound sends a org.varlink.service errror reply to this method call
|
// ReplyInterfaceNotFound sends a org.varlink.service errror reply to this method call
|
||||||
func (c *Call) ReplyInterfaceNotFound(interfaceA string) error {
|
func (c *Call) ReplyInterfaceNotFound(interfaceA string) error {
|
||||||
var out struct {
|
var out InterfaceNotFound
|
||||||
Interface string `json:"interface,omitempty"`
|
|
||||||
}
|
|
||||||
out.Interface = interfaceA
|
out.Interface = interfaceA
|
||||||
return doReplyError(c, "org.varlink.service.InterfaceNotFound", &out)
|
return doReplyError(c, "org.varlink.service.InterfaceNotFound", &out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyMethodNotFound sends a org.varlink.service errror reply to this method call
|
// ReplyMethodNotFound sends a org.varlink.service errror reply to this method call
|
||||||
func (c *Call) ReplyMethodNotFound(method string) error {
|
func (c *Call) ReplyMethodNotFound(method string) error {
|
||||||
var out struct {
|
var out MethodNotFound
|
||||||
Method string `json:"method,omitempty"`
|
|
||||||
}
|
|
||||||
out.Method = method
|
out.Method = method
|
||||||
return doReplyError(c, "org.varlink.service.MethodNotFound", &out)
|
return doReplyError(c, "org.varlink.service.MethodNotFound", &out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyMethodNotImplemented sends a org.varlink.service errror reply to this method call
|
// ReplyMethodNotImplemented sends a org.varlink.service errror reply to this method call
|
||||||
func (c *Call) ReplyMethodNotImplemented(method string) error {
|
func (c *Call) ReplyMethodNotImplemented(method string) error {
|
||||||
var out struct {
|
var out MethodNotImplemented
|
||||||
Method string `json:"method,omitempty"`
|
|
||||||
}
|
|
||||||
out.Method = method
|
out.Method = method
|
||||||
return doReplyError(c, "org.varlink.service.MethodNotImplemented", &out)
|
return doReplyError(c, "org.varlink.service.MethodNotImplemented", &out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyInvalidParameter sends a org.varlink.service errror reply to this method call
|
// ReplyInvalidParameter sends a org.varlink.service errror reply to this method call
|
||||||
func (c *Call) ReplyInvalidParameter(parameter string) error {
|
func (c *Call) ReplyInvalidParameter(parameter string) error {
|
||||||
var out struct {
|
var out InvalidParameter
|
||||||
Parameter string `json:"parameter,omitempty"`
|
|
||||||
}
|
|
||||||
out.Parameter = parameter
|
out.Parameter = parameter
|
||||||
return doReplyError(c, "org.varlink.service.InvalidParameter", &out)
|
return doReplyError(c, "org.varlink.service.InvalidParameter", &out)
|
||||||
}
|
}
|
||||||
|
14
vendor/github.com/varlink/go/varlink/service.go
generated
vendored
14
vendor/github.com/varlink/go/varlink/service.go
generated
vendored
@ -22,6 +22,7 @@ type serviceCall struct {
|
|||||||
Parameters *json.RawMessage `json:"parameters,omitempty"`
|
Parameters *json.RawMessage `json:"parameters,omitempty"`
|
||||||
More bool `json:"more,omitempty"`
|
More bool `json:"more,omitempty"`
|
||||||
Oneway bool `json:"oneway,omitempty"`
|
Oneway bool `json:"oneway,omitempty"`
|
||||||
|
Upgrade bool `json:"upgrade,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceReply struct {
|
type serviceReply struct {
|
||||||
@ -50,7 +51,7 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ServiceTimoutError helps API users to special-case timeouts.
|
// ServiceTimoutError helps API users to special-case timeouts.
|
||||||
type ServiceTimeoutError struct {}
|
type ServiceTimeoutError struct{}
|
||||||
|
|
||||||
func (ServiceTimeoutError) Error() string {
|
func (ServiceTimeoutError) Error() string {
|
||||||
return "service timeout"
|
return "service timeout"
|
||||||
@ -73,7 +74,7 @@ func (s *Service) getInterfaceDescription(c Call, name string) error {
|
|||||||
return c.replyGetInterfaceDescription(description)
|
return c.replyGetInterfaceDescription(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
|
func (s *Service) handleMessage(reader *bufio.Reader, writer *bufio.Writer, request []byte) error {
|
||||||
var in serviceCall
|
var in serviceCall
|
||||||
|
|
||||||
err := json.Unmarshal(request, &in)
|
err := json.Unmarshal(request, &in)
|
||||||
@ -83,7 +84,8 @@ func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := Call{
|
c := Call{
|
||||||
writer: writer,
|
Reader: reader,
|
||||||
|
Writer: writer,
|
||||||
in: &in,
|
in: &in,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ func (s *Service) handleConnection(conn net.Conn, wg *sync.WaitGroup) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.handleMessage(writer, request[:len(request)-1])
|
err = s.handleMessage(reader, writer, request[:len(request)-1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// FIXME: report error
|
// FIXME: report error
|
||||||
//fmt.Fprintf(os.Stderr, "handleMessage: %v", err)
|
//fmt.Fprintf(os.Stderr, "handleMessage: %v", err)
|
||||||
@ -201,11 +203,11 @@ func getListener(protocol string, address string) (net.Listener, error) {
|
|||||||
func (s *Service) refreshTimeout(timeout time.Duration) error {
|
func (s *Service) refreshTimeout(timeout time.Duration) error {
|
||||||
switch l := s.listener.(type) {
|
switch l := s.listener.(type) {
|
||||||
case *net.UnixListener:
|
case *net.UnixListener:
|
||||||
if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
|
if err := l.SetDeadline(time.Now().Add(timeout)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *net.TCPListener:
|
case *net.TCPListener:
|
||||||
if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
|
if err := l.SetDeadline(time.Now().Add(timeout)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user