summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-03-26 09:39:14 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-04-23 14:29:45 +0000
commit8493dba23c73617d9529b7ca13b400d50ac6f455 (patch)
treec0de0c67334b9fa7166e01cae95dc560c1e2455a
parentcf1d884ffa45b342f38a78189bbd86186ce6cbfe (diff)
downloadpodman-8493dba23c73617d9529b7ca13b400d50ac6f455.tar.gz
podman-8493dba23c73617d9529b7ca13b400d50ac6f455.tar.bz2
podman-8493dba23c73617d9529b7ca13b400d50ac6f455.zip
Initial varlink implementation
Signed-off-by: baude <bbaude@redhat.com> Closes: #627 Approved by: mheon
-rw-r--r--.gitignore1
-rw-r--r--Dockerfile.Fedora2
-rw-r--r--Makefile26
-rw-r--r--cmd/podman/info.go2
-rw-r--r--cmd/podman/ioprojectatomicpodman/generate.go3
-rw-r--r--cmd/podman/ioprojectatomicpodman/io.projectatomic.podman.varlink65
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/varlink.go60
-rw-r--r--cmd/podman/version.go39
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman9
-rw-r--r--contrib/varlink/io.projectatomic.podman.service12
-rw-r--r--contrib/varlink/io.projectatomic.podman.socket8
-rw-r--r--docs/podman-varlink.1.md38
-rwxr-xr-xhack/verify-gofmt.sh3
-rw-r--r--libpod/version.go50
-rw-r--r--pkg/varlinkapi/config.go14
-rw-r--r--pkg/varlinkapi/containers.go111
-rw-r--r--pkg/varlinkapi/images.go75
-rw-r--r--pkg/varlinkapi/system.go30
-rw-r--r--test/varlink/run_varlink_tests.sh37
-rw-r--r--test/varlink/test_containers.py99
-rw-r--r--test/varlink/test_images.py71
-rw-r--r--test/varlink/test_system.py21
-rw-r--r--varlink_client.py9
-rw-r--r--vendor.conf1
-rw-r--r--vendor/github.com/varlink/go/.gitignore0
-rw-r--r--vendor/github.com/varlink/go/.travis.yml13
-rw-r--r--vendor/github.com/varlink/go/LICENSE201
-rw-r--r--vendor/github.com/varlink/go/Makefile3
-rw-r--r--vendor/github.com/varlink/go/README.md7
-rw-r--r--vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/generator_test.go85
-rw-r--r--vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go294
-rw-r--r--vendor/github.com/varlink/go/cmd/varlink-go-type-generator/main.go142
-rw-r--r--vendor/github.com/varlink/go/golang-github-varlink-go.spec44
-rw-r--r--vendor/github.com/varlink/go/varlink/call.go86
-rw-r--r--vendor/github.com/varlink/go/varlink/connection.go197
-rw-r--r--vendor/github.com/varlink/go/varlink/doc.go63
-rw-r--r--vendor/github.com/varlink/go/varlink/external_test.go144
-rw-r--r--vendor/github.com/varlink/go/varlink/idl/idl.go465
-rw-r--r--vendor/github.com/varlink/go/varlink/idl/idl_test.go127
-rw-r--r--vendor/github.com/varlink/go/varlink/orgvarlinkservice.go133
-rw-r--r--vendor/github.com/varlink/go/varlink/resolver.go92
-rw-r--r--vendor/github.com/varlink/go/varlink/service.go350
-rw-r--r--vendor/github.com/varlink/go/varlink/varlink_test.go232
45 files changed, 3434 insertions, 32 deletions
diff --git a/.gitignore b/.gitignore
index cc7e7bd3e..c372735f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@
/test/checkseccomp/checkseccomp
/test/copyimg/copyimg
/build/
+cmd/podman/ioprojectatomicpodman/ioprojectatomicpodman.go
diff --git a/Dockerfile.Fedora b/Dockerfile.Fedora
index aa10a054f..1480647c0 100644
--- a/Dockerfile.Fedora
+++ b/Dockerfile.Fedora
@@ -79,4 +79,6 @@ RUN mkdir -p /etc/containers
COPY test/policy.json /etc/containers/policy.json
COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redhat.com.yaml
+# Install varlink stuff
+RUN pip3 install varlink
WORKDIR /go/src/github.com/projectatomic/libpod
diff --git a/Makefile b/Makefile
index 42b7c50f9..bee8d7c00 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,9 @@ MANDIR ?= ${PREFIX}/share/man
SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers
ETCDIR ?= ${DESTDIR}/etc
ETCDIR_LIBPOD ?= ${ETCDIR}/crio
+SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system
BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh)
+PYTHON ?= /usr/bin/python3
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
OCIUMOUNTINSTALLDIR=$(PREFIX)/share/oci-umount/oci-umount.d
@@ -65,7 +67,7 @@ ifeq ("$(wildcard $(GOPKGDIR))","")
endif
touch "$(GOPATH)/.gopathok"
-lint: .gopathok
+lint: .gopathok varlink_generate
@echo "checking lint"
@./.tool/lint
@@ -101,6 +103,7 @@ endif
rm -f test/copyimg/copyimg
rm -f test/checkseccomp/checkseccomp
rm -fr build/
+ rm -f cmd/podman/ioprojectatomicpodman/ioprojectatomicpodman.go
libpodimage:
docker build -t ${LIBPOD_IMAGE} .
@@ -126,19 +129,20 @@ shell: libpodimage
testunit: libpodimage
docker run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make localunit
-localunit:
+localunit: varlink_generate
$(GO) test -tags "$(BUILDTAGS)" -cover $(PACKAGES)
ginkgo:
ginkgo -v test/e2e/
-localintegration: test-binaries
+localintegration: varlink_generate test-binaries
ginkgo -v -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/.
+ sh test/varlink/run_varlink_tests.sh
vagrant-check:
BOX=$(BOX) sh ./vagrant.sh
-binaries: podman
+binaries: varlink_generate podman
test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp
@@ -163,7 +167,7 @@ changelog:
$(shell cat $(TMPFILE) >> changelog.txt)
$(shell rm $(TMPFILE))
-install: .gopathok install.bin install.man install.cni
+install: .gopathok install.bin install.man install.cni install.systemd
install.bin:
install ${SELINUXOPT} -D -m 755 bin/podman $(BINDIR)/podman
@@ -189,6 +193,10 @@ install.docker: docker-docs
install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1
install ${SELINUXOPT} -m 644 docs/docker*.1 -t $(MANDIR)/man1
+install.systemd:
+ install ${SELINUXOPT} -m 644 contrib/varlink/io.projectatomic.podman.socket ${SYSTEMDDIR}/io.projectatomic.podman.socket
+ install ${SELINUXOPT} -m 644 contrib/varlink/io.projectatomic.podman.service ${SYSTEMDDIR}/io.projectatomic.podman.service
+
uninstall:
for i in $(filter %.1,$(MANPAGES)); do \
rm -f $(MANDIR)/man1/$$(basename $${i}); \
@@ -229,6 +237,14 @@ install.tools: .install.gitvalidation .install.gometalinter .install.md2man
make all install; \
fi
+.install.varlink: .gopathok
+ $(GO) get -u github.com/varlink/go/varlink
+ $(GO) get -u github.com/varlink/go/cmd/varlink-go-interface-generator
+
+varlink_generate: .gopathok .install.varlink
+ rm -f cmd/podman/ioprojectatomicpodman/ioprojectatomicpodman.go
+ $(GO) generate ./cmd/podman/ioprojectatomicpodman/...
+
validate: gofmt .gitvalidation
.PHONY: \
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index 89f32a258..1c4ba2515 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -79,6 +79,6 @@ func debugInfo(c *cli.Context) map[string]interface{} {
info["compiler"] = runtime.Compiler
info["go version"] = runtime.Version()
info["podman version"] = c.App.Version
- info["git commit"] = gitCommit
+ info["git commit"] = libpod.GitCommit
return info
}
diff --git a/cmd/podman/ioprojectatomicpodman/generate.go b/cmd/podman/ioprojectatomicpodman/generate.go
new file mode 100644
index 000000000..b24234f0a
--- /dev/null
+++ b/cmd/podman/ioprojectatomicpodman/generate.go
@@ -0,0 +1,3 @@
+package ioprojectatomicpodman
+
+//go:generate $GOPATH/bin/varlink-go-interface-generator io.projectatomic.podman.varlink
diff --git a/cmd/podman/ioprojectatomicpodman/io.projectatomic.podman.varlink b/cmd/podman/ioprojectatomicpodman/io.projectatomic.podman.varlink
new file mode 100644
index 000000000..00a99017c
--- /dev/null
+++ b/cmd/podman/ioprojectatomicpodman/io.projectatomic.podman.varlink
@@ -0,0 +1,65 @@
+# Podman Service Interface
+interface io.projectatomic.podman
+
+type Version (
+ version: string,
+ go_version: string,
+ git_commit: string,
+ built: int,
+ os_arch: string
+)
+
+type NotImplemented (
+ comment: string
+)
+
+type StringResponse (
+ message: string
+)
+
+# System
+method Ping() -> (ping: StringResponse)
+method GetVersion() -> (version: Version)
+
+# Containers
+method ListContainers() -> (notimplemented: NotImplemented)
+method CreateContainer() -> (notimplemented: NotImplemented)
+method InspectContainer() -> (notimplemented: NotImplemented)
+method ListContainerProcesses() -> (notimplemented: NotImplemented)
+method GetContainerLogs() -> (notimplemented: NotImplemented)
+method ListContainerChanges() -> (notimplemented: NotImplemented)
+method ExportContainer() -> (notimplemented: NotImplemented)
+method GetContainerStats() -> (notimplemented: NotImplemented)
+method ResizeContainerTty() -> (notimplemented: NotImplemented)
+method StartContainer() -> (notimplemented: NotImplemented)
+method StopContainer() -> (notimplemented: NotImplemented)
+method RestartContainer() -> (notimplemented: NotImplemented)
+method KillContainer() -> (notimplemented: NotImplemented)
+method UpdateContainer() -> (notimplemented: NotImplemented)
+method RenameContainer() -> (notimplemented: NotImplemented)
+method PauseContainer() -> (notimplemented: NotImplemented)
+method UnpauseContainer() -> (notimplemented: NotImplemented)
+method AttachToContainer() -> (notimplemented: NotImplemented)
+method WaitContainer() -> (notimplemented: NotImplemented)
+method RemoveContainer() -> (notimplemented: NotImplemented)
+method DeleteStoppedContainers() -> (notimplemented: NotImplemented)
+
+# Images
+method ListImages() -> (notimplemented: NotImplemented)
+method BuildImage() -> (notimplemented: NotImplemented)
+method CreateImage() -> (notimplemented: NotImplemented)
+method InspectImage() -> (notimplemented: NotImplemented)
+method HistoryImage() -> (notimplemented: NotImplemented)
+method PushImage() -> (notimplemented: NotImplemented)
+method TagImage() -> (notimplemented: NotImplemented)
+method RemoveImage() -> (notimplemented: NotImplemented)
+method SearchImage() -> (notimplemented: NotImplemented)
+method DeleteUnusedImages() -> (notimplemented: NotImplemented)
+method CreateFromContainer() -> (notimplemented: NotImplemented)
+method ImportImage() -> (notimplemented: NotImplemented)
+method ExportImage() -> (notimplemented: NotImplemented)
+method PullImage() -> (notimplemented: NotImplemented)
+
+
+# Something failed
+error ActionFailed (reason: string)
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index ef11f7905..a283c2622 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -70,6 +70,7 @@ func main() {
topCommand,
umountCommand,
unpauseCommand,
+ varlinkCommand,
versionCommand,
waitCommand,
}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
new file mode 100644
index 000000000..75ddc6c4d
--- /dev/null
+++ b/cmd/podman/varlink.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+ "github.com/pkg/errors"
+ "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ "github.com/projectatomic/libpod/pkg/varlinkapi"
+ "github.com/projectatomic/libpod/version"
+ "github.com/urfave/cli"
+ "github.com/varlink/go/varlink"
+)
+
+var (
+ varlinkDescription = `
+ podman varlink
+
+ run varlink interface
+`
+ varlinkFlags = []cli.Flag{}
+ varlinkCommand = cli.Command{
+ Name: "varlink",
+ Usage: "Run varlink interface",
+ Description: varlinkDescription,
+ Flags: varlinkFlags,
+ Action: varlinkCmd,
+ ArgsUsage: "VARLINK_URI",
+ }
+)
+
+func varlinkCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) < 1 {
+ return errors.Errorf("you must provide a varlink URI")
+ }
+
+ var varlinkInterfaces = []*ioprojectatomicpodman.VarlinkInterface{varlinkapi.VarlinkLibpod}
+ // Register varlink service. The metadata can be retrieved with:
+ // $ varlink info [varlink address URI]
+ service, err := varlink.NewService(
+ "Atomic",
+ "podman",
+ version.Version,
+ "https://github.com/projectatomic/libpod",
+ )
+ if err != nil {
+ return errors.Wrapf(err, "unable to create new varlink service")
+ }
+
+ for _, i := range varlinkInterfaces {
+ if err := service.RegisterInterface(i); err != nil {
+ return errors.Errorf("unable to register varlink interface %v", i)
+ }
+ }
+
+ // Run the varlink server at the given address
+ if err = service.Listen(args[0], 0); err != nil {
+ return errors.Errorf("unable to start varlink service")
+ }
+
+ return nil
+}
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index be9b406e7..952cf32d3 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -2,41 +2,30 @@ package main
import (
"fmt"
- "runtime"
- "strconv"
"time"
+ "github.com/pkg/errors"
+ "github.com/projectatomic/libpod/libpod"
"github.com/urfave/cli"
)
-// Overwritten at build time
-var (
- // gitCommit is the commit that the binary is being built from.
- // It will be populated by the Makefile.
- gitCommit string
- // buildInfo is the time at which the binary was built
- // It will be populated by the Makefile.
- buildInfo string
-)
-
// versionCmd gets and prints version info for version command
func versionCmd(c *cli.Context) error {
- fmt.Println("Version: ", c.App.Version)
- fmt.Println("Go Version: ", runtime.Version())
- if gitCommit != "" {
- fmt.Println("Git Commit: ", gitCommit)
+ output, err := libpod.GetVersion()
+ if err != nil {
+ errors.Wrapf(err, "unable to determine version")
+ }
+ fmt.Println("Version: ", output.Version)
+ fmt.Println("Go Version: ", output.GoVersion)
+ if output.GitCommit != "" {
+ fmt.Println("Git Commit: ", output.GitCommit)
}
- if buildInfo != "" {
- // Converts unix time from string to int64
- buildTime, err := strconv.ParseInt(buildInfo, 10, 64)
- if err != nil {
- return err
- }
- // Prints out the build time in readable format
- fmt.Println("Built: ", time.Unix(buildTime, 0).Format(time.ANSIC))
+ // Prints out the build time in readable format
+ if libpod.BuildInfo != "" {
+ fmt.Println("Built: ", time.Unix(output.Built, 0).Format(time.ANSIC))
}
- fmt.Println("OS/Arch: ", runtime.GOOS+"/"+runtime.GOARCH)
+ fmt.Println("OS/Arch: ", output.OsArch)
return nil
}
diff --git a/commands.md b/commands.md
index da6852b01..a55bc3612 100644
--- a/commands.md
+++ b/commands.md
@@ -42,5 +42,6 @@
| [podman-top(1)](/docs/podman-top.1.md) | Display the running processes of a container |[![...](/docs/play.png)](https://asciinema.org/a/5WCCi1LXwSuRbvaO9cBUYf3fk)|
| [podman-umount(1)](/docs/podman-umount.1.md) | Unmount a working container's root filesystem |[![...](/docs/play.png)](https://asciinema.org/a/MZPTWD5CVs3dMREkBxQBY9C5z)|
| [podman-unpause(1)](/docs/podman-unpause.1.md) | Unpause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)|
+| [podman-varlink(1)](/docs/podman-varlink.1.md) | Run the varlink backend ||
| [podman-version(1)](/docs/podman-version.1.md) | Display the version information |[![...](/docs/play.png)](https://asciinema.org/a/mfrn61pjZT9Fc8L4NbfdSqfgu)|
| [podman-wait(1)](/docs/podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes |[![...](/docs/play.png)](https://asciinema.org/a/QNPGKdjWuPgI96GcfkycQtah0)|
diff --git a/completions/bash/podman b/completions/bash/podman
index 3cb48b156..4c9be0ab2 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1514,6 +1514,14 @@ _podman_unpause() {
_complete_ "$options_with_args" "$boolean_options"
}
+_podman_varlink() {
+ local options_with_args="
+ --help -h
+ "
+ local boolean_options=""
+ _complete_ "$options_with_args" "$boolean_options"
+}
+
_podman_wait() {
local options_with_args=""
local boolean_options="
@@ -1633,6 +1641,7 @@ _podman_podman() {
umount
unmount
unpause
+ varlink
version
wait
"
diff --git a/contrib/varlink/io.projectatomic.podman.service b/contrib/varlink/io.projectatomic.podman.service
new file mode 100644
index 000000000..5b5c43134
--- /dev/null
+++ b/contrib/varlink/io.projectatomic.podman.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Pod Manager
+Requires=io.projectatomic.podman.socket
+After=io.projectatomic.podman.socket
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/podman --varlink=unix:/run/io.projectatomic.podman
+
+[Install]
+WantedBy=multi-user.target
+Also=io.projectatomic.podman.socket
diff --git a/contrib/varlink/io.projectatomic.podman.socket b/contrib/varlink/io.projectatomic.podman.socket
new file mode 100644
index 000000000..d49b458a0
--- /dev/null
+++ b/contrib/varlink/io.projectatomic.podman.socket
@@ -0,0 +1,8 @@
+[Unit]
+Description=Pod Manager Socket
+
+[Socket]
+ListenStream=/run/io.projectatomic.podman
+
+[Install]
+WantedBy=sockets.target
diff --git a/docs/podman-varlink.1.md b/docs/podman-varlink.1.md
new file mode 100644
index 000000000..af50ad9dc
--- /dev/null
+++ b/docs/podman-varlink.1.md
@@ -0,0 +1,38 @@
+% podman(1) podman-varlink - Waits on a container
+% Brent Baude
+# podman-varlink "1" "April 2018" "podman"
+
+## NAME
+podman varlink - Runs the varlink backend interface
+
+## SYNOPSIS
+**podman varlink**
+[**--help**|**-h**]
+VARLINK_URI
+
+## DESCRIPTION
+Starts the varlink service that allows varlink clients to interact with podman.
+<!--
+More will go here as the docs and api firm up.
+-->
+
+**podman [GLOBAL OPTIONS] varlink **
+
+## GLOBAL OPTIONS
+
+**--help, -h**
+ Print usage statement
+
+## EXAMPLES
+
+ podman varlink unix:/run/io.projectatomic.podman
+<!--
+ TODO: More examples with TCP can be added when that works
+ as well.
+-->
+
+## SEE ALSO
+podman(1)
+
+## HISTORY
+April 2018, Originally compiled by Brent Baude<bbaude@redhat.com>
diff --git a/hack/verify-gofmt.sh b/hack/verify-gofmt.sh
index c11ab3adb..af252a13b 100755
--- a/hack/verify-gofmt.sh
+++ b/hack/verify-gofmt.sh
@@ -10,7 +10,8 @@ find_files() {
-wholename '*/vendor/*' \
\) -prune \
\) -name '*.go' \
- -not \( -wholename './_output/*' \)
+ -not \( -wholename './_output/*' \) \
+ -not \( -wholename './cmd/podman/ioprojectatomicpodman/ioprojectatomicpodman.go' \)
}
FIX=0
GOFMT="gofmt -s"
diff --git a/libpod/version.go b/libpod/version.go
new file mode 100644
index 000000000..9bc4fe616
--- /dev/null
+++ b/libpod/version.go
@@ -0,0 +1,50 @@
+package libpod
+
+import (
+ "runtime"
+ "strconv"
+
+ "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ podmanVersion "github.com/projectatomic/libpod/version"
+)
+
+// Overwritten at build time
+var (
+ // GitCommit is the commit that the binary is being built from.
+ // It will be populated by the Makefile.
+ GitCommit string
+ // BuildInfo is the time at which the binary was built
+ // It will be populated by the Makefile.
+ BuildInfo string
+)
+
+//Version is an output struct for varlink
+type Version struct {
+ ioprojectatomicpodman.VarlinkInterface
+ Version string
+ GoVersion string
+ GitCommit string
+ Built int64
+ OsArch string
+}
+
+// GetVersion returns a VersionOutput struct for varlink and podman
+func GetVersion() (Version, error) {
+ var err error
+ var buildTime int64
+ if BuildInfo != "" {
+ // Converts unix time from string to int64
+ buildTime, err = strconv.ParseInt(BuildInfo, 10, 64)
+
+ if err != nil {
+ return Version{}, err
+ }
+ }
+ return Version{
+ Version: podmanVersion.Version,
+ GoVersion: runtime.Version(),
+ GitCommit: GitCommit,
+ Built: buildTime,
+ OsArch: runtime.GOOS + "/" + runtime.GOARCH,
+ }, nil
+}
diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go
new file mode 100644
index 000000000..167270f09
--- /dev/null
+++ b/pkg/varlinkapi/config.go
@@ -0,0 +1,14 @@
+package varlinkapi
+
+import "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+
+// LibpodAPI is the basic varlink struct for libpod
+type LibpodAPI struct {
+ ioprojectatomicpodman.VarlinkInterface
+}
+
+var (
+ lp = LibpodAPI{}
+ // VarlinkLibpod instantiation
+ VarlinkLibpod = ioprojectatomicpodman.VarlinkNew(&lp)
+)
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
new file mode 100644
index 000000000..e58cab497
--- /dev/null
+++ b/pkg/varlinkapi/containers.go
@@ -0,0 +1,111 @@
+package varlinkapi
+
+import (
+ "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+)
+
+// ListContainers ...
+func (i *LibpodAPI) ListContainers(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ListContainers")
+}
+
+// CreateContainer ...
+func (i *LibpodAPI) CreateContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("CreateContainer")
+}
+
+// InspectContainer ...
+func (i *LibpodAPI) InspectContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("InspectContainer")
+}
+
+// ListContainerProcesses ...
+func (i *LibpodAPI) ListContainerProcesses(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ListContainerProcesses")
+}
+
+// GetContainerLogs ...
+func (i *LibpodAPI) GetContainerLogs(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("GetContainerLogs")
+}
+
+// ListContainerChanges ...
+func (i *LibpodAPI) ListContainerChanges(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ListContianerChanges")
+}
+
+// ExportContainer ...
+func (i *LibpodAPI) ExportContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ExportContainer")
+}
+
+// GetContainerStats ...
+func (i *LibpodAPI) GetContainerStats(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("GetContainerStates")
+}
+
+// ResizeContainerTty ...
+func (i *LibpodAPI) ResizeContainerTty(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ResizeContainerTty")
+}
+
+// StartContainer ...
+func (i *LibpodAPI) StartContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("StartContainer")
+}
+
+// StopContainer ...
+func (i *LibpodAPI) StopContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("StopContainer")
+}
+
+// RestartContainer ...
+func (i *LibpodAPI) RestartContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("RestartContainer")
+}
+
+// KillContainer ...
+func (i *LibpodAPI) KillContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("KillContainer")
+}
+
+// UpdateContainer ...
+func (i *LibpodAPI) UpdateContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("UpdateContainer")
+}
+
+// RenameContainer ...
+func (i *LibpodAPI) RenameContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("RenameContainer")
+}
+
+// PauseContainer ...
+func (i *LibpodAPI) PauseContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("PauseContainer")
+}
+
+// UnpauseContainer ...
+func (i *LibpodAPI) UnpauseContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("UnpauseContainer")
+}
+
+// AttachToContainer ...
+// TODO: DO we also want a different one for websocket?
+func (i *LibpodAPI) AttachToContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("AttachToContainer")
+}
+
+// WaitContainer ...
+func (i *LibpodAPI) WaitContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("WaitContainer")
+}
+
+// RemoveContainer ...
+func (i *LibpodAPI) RemoveContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("RemoveContainer")
+}
+
+// DeleteStoppedContainers ...
+func (i *LibpodAPI) DeleteStoppedContainers(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("DeleteContainer")
+}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
new file mode 100644
index 000000000..1de54e43b
--- /dev/null
+++ b/pkg/varlinkapi/images.go
@@ -0,0 +1,75 @@
+package varlinkapi
+
+import (
+ "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+)
+
+// ListImages ...
+func (i *LibpodAPI) ListImages(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ListImages")
+}
+
+// BuildImage ...
+func (i *LibpodAPI) BuildImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("BuildImage")
+}
+
+// CreateImage ...
+func (i *LibpodAPI) CreateImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("CreateImage")
+}
+
+// InspectImage ...
+func (i *LibpodAPI) InspectImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("InspectImage")
+}
+
+// HistoryImage ...
+func (i *LibpodAPI) HistoryImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("HistoryImage")
+}
+
+// PushImage ...
+func (i *LibpodAPI) PushImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("PushImage")
+}
+
+// TagImage ...
+func (i *LibpodAPI) TagImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("TagImage")
+}
+
+// RemoveImage ...
+func (i *LibpodAPI) RemoveImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("RemoveImage")
+}
+
+// SearchImage ...
+func (i *LibpodAPI) SearchImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("SearchImage")
+}
+
+// DeleteUnusedImages ...
+func (i *LibpodAPI) DeleteUnusedImages(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("DeleteUnusedImages")
+}
+
+// CreateFromContainer ...
+func (i *LibpodAPI) CreateFromContainer(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("CreateFromContainer")
+}
+
+// ImportImage ...
+func (i *LibpodAPI) ImportImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ImportImage")
+}
+
+// ExportImage ...
+func (i *LibpodAPI) ExportImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("ExportImage")
+}
+
+// PullImage ...
+func (i *LibpodAPI) PullImage(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyMethodNotImplemented("PullImage")
+}
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
new file mode 100644
index 000000000..c343f1245
--- /dev/null
+++ b/pkg/varlinkapi/system.go
@@ -0,0 +1,30 @@
+package varlinkapi
+
+import (
+ "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ "github.com/projectatomic/libpod/libpod"
+)
+
+// GetVersion ...
+func (i *LibpodAPI) GetVersion(call ioprojectatomicpodman.VarlinkCall) error {
+ versionInfo, err := libpod.GetVersion()
+ if err != nil {
+ return err
+ }
+
+ return call.ReplyGetVersion(ioprojectatomicpodman.Version{
+ Version: versionInfo.Version,
+ Go_version: versionInfo.GoVersion,
+ Git_commit: versionInfo.GitCommit,
+ Built: versionInfo.Built,
+ Os_arch: versionInfo.OsArch,
+ })
+}
+
+// Ping returns a simple string "OK" response for clients to make sure
+// the service is working.
+func (i *LibpodAPI) Ping(call ioprojectatomicpodman.VarlinkCall) error {
+ return call.ReplyPing(ioprojectatomicpodman.StringResponse{
+ Message: "OK",
+ })
+}
diff --git a/test/varlink/run_varlink_tests.sh b/test/varlink/run_varlink_tests.sh
new file mode 100644
index 000000000..9c247fec2
--- /dev/null
+++ b/test/varlink/run_varlink_tests.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+set -x
+if [ ! -n "${PYTHON+ }" ]; then
+ if hash python3 > /dev/null 2>&1 /dev/null; then
+ PYTHON=$(hash -t python3)
+ elif type python3 > /dev/null 2>&1; then
+ PYTHON=$(type python3 | awk '{print $3}')
+ elif hash python2 > /dev/null 2>&1; then
+ PYTHON=$(hash -t python2)
+ elif type python2 > /dev/null 2>&1; then
+ PYTHON=$(type python2 | awk '{print $3}')
+ else
+ PYTHON='/usr/bin/python'
+ fi
+fi
+
+# Create temporary directory for storage
+TMPSTORAGE=`mktemp -d`
+
+# Need a location to store the podman socket
+mkdir /run/podman
+
+# Run podman in background without systemd for test purposes
+bin/podman --storage-driver=vfs --root=${TMPSTORAGE}/crio --runroot=${TMPSTORAGE}/crio-run varlink unix:/run/podman/io.projectatomic.podman&
+
+# Record podman's pid to be killed later
+PODMAN_PID=`echo $!`
+
+# Run tests
+${PYTHON} -m unittest discover -s test/varlink/
+
+# Kill podman
+kill -9 ${PODMAN_PID}
+
+# Clean up
+rm -fr ${TMPSTORAGE}
diff --git a/test/varlink/test_containers.py b/test/varlink/test_containers.py
new file mode 100644
index 000000000..651461d55
--- /dev/null
+++ b/test/varlink/test_containers.py
@@ -0,0 +1,99 @@
+import unittest
+from varlink import (Client, VarlinkError)
+
+
+address = "unix:/run/podman/io.projectatomic.podman"
+client = Client(address=address)
+
+
+def runErrorTest(tfunc):
+ try:
+ tfunc()
+ except VarlinkError as e:
+ return e.error() == "org.varlink.service.MethodNotImplemented"
+ return False
+
+
+class ContainersAPI(unittest.TestCase):
+ def test_ListContainers(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ListContainers))
+
+ def test_CreateContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.CreateContainer))
+
+ def test_InspecContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.InspectContainer))
+
+ def test_ListContainerProcesses(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ListContainerProcesses))
+
+ def test_GetContainerLogs(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.GetContainerLogs))
+
+ def test_ListContainerChanges(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ListContainerChanges))
+
+ def test_ExportContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ExportContainer))
+
+ def test_GetContainerStats(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.GetContainerStats))
+
+ def test_ResizeContainerTty(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ResizeContainerTty))
+
+ def test_StartContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.StartContainer))
+
+ def test_RestartContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.RestartContainer))
+
+ def test_KillContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.KillContainer))
+
+ def test_UpdateContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.UpdateContainer))
+
+ def test_RenameContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.RenameContainer))
+
+ def test_PauseContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.PauseContainer))
+
+ def test_UnpauseContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.UnpauseContainer))
+
+ def test_AttachToContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.AttachToContainer))
+
+ def test_WaitContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.WaitContainer))
+
+ def test_RemoveContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.RemoveContainer))
+
+ def test_DeleteContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.DeleteContainer))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/varlink/test_images.py b/test/varlink/test_images.py
new file mode 100644
index 000000000..ef1ab1088
--- /dev/null
+++ b/test/varlink/test_images.py
@@ -0,0 +1,71 @@
+import unittest
+from varlink import (Client, VarlinkError)
+
+
+address = "unix:/run/podman/io.projectatomic.podman"
+client = Client(address=address)
+
+
+def runErrorTest(tfunc):
+ try:
+ tfunc()
+ except VarlinkError as e:
+ return e.error() == "org.varlink.service.MethodNotImplemented"
+ return False
+
+
+class ImagesAPI(unittest.TestCase):
+ def test_ListImages(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ListImages))
+
+ def test_BuildImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.BuildImage))
+
+ def test_CreateImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.CreateImage))
+
+ def test_InspectImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.InspectImage))
+
+ def test_HistoryImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.HistoryImage))
+
+ def test_PushImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.PushImage))
+
+ def test_TagImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.TagImage))
+
+ def test_RemoveImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.TagImage))
+
+ def test_SearchImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.SearchImage))
+
+ def test_DeleteUnusedImages(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.DeleteUnusedImages))
+
+ def test_CreateFromContainer(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.CreateFromContainer))
+
+ def test_ImportImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ImportImage))
+
+ def test_ExportImage(self):
+ podman = client.open("io.projectatomic.podman")
+ self.assertTrue(runErrorTest(podman.ExportImage))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/varlink/test_system.py b/test/varlink/test_system.py
new file mode 100644
index 000000000..6180d2068
--- /dev/null
+++ b/test/varlink/test_system.py
@@ -0,0 +1,21 @@
+import unittest
+from varlink import (Client, VarlinkError)
+
+
+address = "unix:/run/podman/io.projectatomic.podman"
+client = Client(address=address)
+
+class SystemAPI(unittest.TestCase):
+ def test_ping(self):
+ podman = client.open("io.projectatomic.podman")
+ response = podman.Ping()
+ self.assertEqual("OK", response["ping"]["message"])
+
+ def test_GetVersion(self):
+ podman = client.open("io.projectatomic.podman")
+ response = podman.GetVersion()
+ for k in ["version", "go_version", "built", "os_arch"]:
+ self.assertTrue(k in response["version"].keys())
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/varlink_client.py b/varlink_client.py
new file mode 100644
index 000000000..7446e3012
--- /dev/null
+++ b/varlink_client.py
@@ -0,0 +1,9 @@
+from varlink import (Client, VarlinkError)
+import json
+
+address = "unix:/run/podman/io.projectatomic.podman"
+
+with Client(address=address) as client:
+ podman = client.open('io.projectatomic.podman')
+ response = podman.GetVersion()
+ print(json.dumps(response, indent=4, separators=(',', ': '))) \ No newline at end of file
diff --git a/vendor.conf b/vendor.conf
index f7e2b5abb..487431232 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -87,3 +87,4 @@ k8s.io/client-go 7cd1d3291b7d9b1e2d54d4b69eb65995eaf8888e https://github.com/kub
k8s.io/kube-openapi 275e2ce91dec4c05a4094a7b1daee5560b555ac9 https://github.com/kubernetes/kube-openapi
k8s.io/utils 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e https://github.com/kubernetes/utils
github.com/mrunalp/fileutils master
+github.com/varlink/go master https://github.com/varlink/go
diff --git a/vendor/github.com/varlink/go/.gitignore b/vendor/github.com/varlink/go/.gitignore
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/varlink/go/.gitignore
diff --git a/vendor/github.com/varlink/go/.travis.yml b/vendor/github.com/varlink/go/.travis.yml
new file mode 100644
index 000000000..990f12e0a
--- /dev/null
+++ b/vendor/github.com/varlink/go/.travis.yml
@@ -0,0 +1,13 @@
+language: go
+sudo: false
+go:
+- '1.9'
+- 1.10.x
+install:
+- go get golang.org/x/tools/cmd/cover
+- go get github.com/mattn/goveralls
+script:
+- '"$HOME/gopath/bin/goveralls" -show -service=travis-ci -repotoken "$COVERALLS_TOKEN"'
+env:
+ global:
+ - secure: bjxOSgBfB+YooxNTkIDHAD+/X6g56qBWoYpB1JinuS5kmt3vSjfRSuXui71sGuha7jO2FOJja8HcpjOv3UP+qmmej9276o5VWrjS1AwnI95hSQQ4JHm293Z1QeojjRaxmoKrgn7i82Hn4qNdVLQA142s+SIdqOxtN6LDs7i0Yb4IuXoiMQHbd6kAAL95o9IUFPpYAdsXoQ6xnx+TXNiSwPPeh4m5CNKuTtmGTuMGaj8tXxttFKJhZcRzvOpDuh7luc9PSVnQgYmKE/3S9ehzGV8Lk4T8eC7587DY1GdYQKt1egJSE72L+PVnmoalWROaAGHZvYWsSAeNi1UIvcFwGbXBRpq7kz3DVfIULM8V67UAaF3dGYDN3Ae825mDjN5JDfml17AoEjMjI0LlBImZLX2EWIEN225JIREHdpG9seJkaN1ClcpvEIeYuThF2MiivP1EE8/w8S80yoO5nW76Py/th16OuaEiP9LdLsbXimObUPsS9Sr8qquf/PiVqRMMpVW88oOEG5HVn4Ra5B/xVC6nPEF88tE6p9+7RSz4rOWih8QmW+6SX6eo0BI9di4L779f/WfUrddN0JLIvEnRFZZ+pVF/oo+N2INNeIMsZBvG3FVo+Zxzo6SExXnSSpuf1bp140ZdinUMACq6BqK+9gj1C9vNRmqQJaEefrqutws=
diff --git a/vendor/github.com/varlink/go/LICENSE b/vendor/github.com/varlink/go/LICENSE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/vendor/github.com/varlink/go/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/varlink/go/Makefile b/vendor/github.com/varlink/go/Makefile
new file mode 100644
index 000000000..3f1c0e6d6
--- /dev/null
+++ b/vendor/github.com/varlink/go/Makefile
@@ -0,0 +1,3 @@
+all:
+ go test -v ./...
+.PHONY: all
diff --git a/vendor/github.com/varlink/go/README.md b/vendor/github.com/varlink/go/README.md
new file mode 100644
index 000000000..926a82bdd
--- /dev/null
+++ b/vendor/github.com/varlink/go/README.md
@@ -0,0 +1,7 @@
+[![Build Status](https://travis-ci.org/varlink/go.svg?branch=master)](https://travis-ci.org/varlink/go)
+[![Go Report Card](https://goreportcard.com/badge/github.com/varlink/go)](https://goreportcard.com/report/github.com/varlink/go)
+[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/varlink/go/varlink)
+[![Coverage Status](https://coveralls.io/repos/github/varlink/go/badge.svg?branch=master)](https://coveralls.io/github/varlink/go?branch=master)
+[![Release](https://img.shields.io/github/release/golang-standards/project-layout.svg?style=flat-square)](https://github.com/varlink/go/varlink/releases/latest)
+
+# go/varlink
diff --git a/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/generator_test.go b/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/generator_test.go
new file mode 100644
index 000000000..aa3a8565f
--- /dev/null
+++ b/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/generator_test.go
@@ -0,0 +1,85 @@
+package main
+
+import (
+ "strings"
+ "testing"
+)
+
+func expect(t *testing.T, expected string, returned string) {
+ if strings.Compare(returned, expected) != 0 {
+ t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
+ len(expected), expected,
+ len(returned), returned)
+ }
+}
+
+func TestIDLParser(t *testing.T) {
+ pkgname, b, err := generateTemplate(`
+# Interface to jump a spacecraft to another point in space. The
+# FTL Drive is the propulsion system to achieve faster-than-light
+# travel through space. A ship making a properly calculated
+# jump can arrive safely in planetary orbit, or alongside other
+# ships or spaceborne objects.
+interface org.example.ftl
+
+# The current state of the FTL drive and the amount of fuel
+# available to jump.
+type DriveCondition (
+ state: (idle, spooling, busy),
+ booster: bool,
+ active_engines: [](id: int, state: bool),
+ tylium_level: int
+)
+
+# Speed, trajectory and jump duration is calculated prior to
+# activating the FTL drive.
+type DriveConfiguration (
+ speed: int,
+ trajectory: int,
+ duration: int
+)
+
+# The galactic coordinates use the Sun as the origin. Galactic
+# longitude is measured with primary direction from the Sun to
+# the center of the galaxy in the galactic plane, while the
+# galactic latitude measures the angle of the object above the
+# galactic plane.
+type Coordinate (
+ longitude: float,
+ latitude: float,
+ distance: int
+)
+
+# Monitor the drive. The method will reply with an update whenever
+# the drive's state changes
+method Monitor() -> (condition: DriveCondition)
+
+# Calculate the drive's jump parameters from the current
+# position to the target position in the galaxy
+method CalculateConfiguration(
+ current: Coordinate,
+ target: Coordinate
+) -> (configuration: DriveConfiguration)
+
+# Jump to the calculated point in space
+method Jump(configuration: DriveConfiguration) -> ()
+
+# There is not enough tylium to jump with the given parameters
+error NotEnoughEnergy ()
+
+# The supplied parameters are outside the supported range
+error ParameterOutOfRange (field: string)
+
+# some more coverage
+method Foo(interface: string) -> (ret: (go: string, switch: bool, more: (t:bool, f:bool)))
+ `)
+
+ if err != nil {
+ t.Fatalf("Error parsing %v", err)
+ }
+ expect(t, "orgexampleftl", pkgname)
+ if len(b) <= 0 {
+ t.Fatal("No generated go source")
+ }
+ // FIXME: compare b.String() against expected output
+}
diff --git a/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go b/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go
new file mode 100644
index 000000000..1bcdb78de
--- /dev/null
+++ b/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go
@@ -0,0 +1,294 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "strings"
+
+ "github.com/varlink/go/varlink/idl"
+)
+
+var goKeywords = map[string]struct{}{
+ "break": {},
+ "case": {},
+ "chan": {},
+ "const": {},
+ "continue": {},
+ "default": {},
+ "defer": {},
+ "else": {},
+ "fallthrough": {},
+ "for": {},
+ "func": {},
+ "go": {},
+ "goto": {},
+ "if": {},
+ "import": {},
+ "interface": {},
+ "map": {},
+ "package": {},
+ "range": {},
+ "return": {},
+ "select": {},
+ "struct": {},
+ "switch": {},
+ "type": {},
+ "var": {},
+}
+
+func sanitizeGoName(name string) string {
+ if _, ok := goKeywords[name]; !ok {
+ return name
+ }
+ return name + "_"
+}
+
+func writeType(b *bytes.Buffer, t *idl.Type, json bool, ident int) {
+ switch t.Kind {
+ case idl.TypeBool:
+ b.WriteString("bool")
+
+ case idl.TypeInt:
+ b.WriteString("int64")
+
+ case idl.TypeFloat:
+ b.WriteString("float64")
+
+ case idl.TypeString, idl.TypeEnum:
+ b.WriteString("string")
+
+ case idl.TypeArray:
+ b.WriteString("[]")
+ writeType(b, t.ElementType, json, ident)
+
+ case idl.TypeMaybe:
+ b.WriteString("*")
+ writeType(b, t.ElementType, json, ident)
+
+ case idl.TypeAlias:
+ b.WriteString(t.Alias)
+
+ case idl.TypeStruct:
+ b.WriteString("struct{\n")
+ for _, field := range t.Fields {
+ for i := 0; i < ident+1; i++ {
+ b.WriteString("\t")
+ }
+
+ b.WriteString(strings.Title(field.Name) + " ")
+ writeType(b, field.Type, json, ident+1)
+ if json {
+ b.WriteString(" `json:\"" + field.Name + "\"`")
+ }
+ b.WriteString("\n")
+ }
+ for i := 0; i < ident; i++ {
+ b.WriteString("\t")
+ }
+ b.WriteString("}")
+ }
+}
+
+func generateTemplate(description string) (string, []byte, error) {
+ description = strings.TrimRight(description, "\n")
+
+ midl, err := idl.New(description)
+ if err != nil {
+ return "", nil, err
+ }
+
+ pkgname := strings.Replace(midl.Name, ".", "", -1)
+
+ var b bytes.Buffer
+ b.WriteString("// Generated with github.com/varlink/go/cmd/varlink-go-interface-generator\n")
+ b.WriteString("package " + pkgname + "\n\n")
+ b.WriteString(`import "github.com/varlink/go/varlink"` + "\n\n")
+
+ // Type declarations
+ for _, a := range midl.Aliases {
+ b.WriteString("type " + a.Name + " ")
+ writeType(&b, a.Type, true, 0)
+ b.WriteString("\n\n")
+ }
+
+ // Local interface with all methods
+ b.WriteString("type " + pkgname + "Interface interface {\n")
+ for _, m := range midl.Methods {
+ b.WriteString("\t" + m.Name + "(c VarlinkCall")
+ for _, field := range m.In.Fields {
+ b.WriteString(", " + strings.Title(field.Name) + " ")
+ writeType(&b, field.Type, false, 1)
+ }
+ b.WriteString(") error\n")
+ }
+ b.WriteString("}\n\n")
+
+ // Local object with all methods
+ b.WriteString("type VarlinkCall struct{ varlink.Call }\n\n")
+
+ // Reply methods for all varlink errors
+ for _, e := range midl.Errors {
+ b.WriteString("func (c *VarlinkCall) Reply" + e.Name + "(")
+ for i, field := range e.Type.Fields {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(sanitizeGoName(field.Name) + " ")
+ writeType(&b, field.Type, false, 1)
+ }
+ b.WriteString(") error {\n")
+ if len(e.Type.Fields) > 0 {
+ b.WriteString("\tvar out ")
+ writeType(&b, e.Type, true, 1)
+ b.WriteString("\n")
+ for _, field := range e.Type.Fields {
+ switch field.Type.Kind {
+ case idl.TypeStruct, idl.TypeArray:
+ b.WriteString("\tout." + strings.Title(field.Name) + " = ")
+ writeType(&b, field.Type, true, 1)
+ b.WriteString("(" + sanitizeGoName(field.Name) + ")\n")
+
+ default:
+ b.WriteString("\tout." + strings.Title(field.Name) + " = " + sanitizeGoName(field.Name) + "\n")
+ }
+ }
+ b.WriteString("\treturn c.ReplyError(\"" + midl.Name + "." + e.Name + "\", &out)\n")
+ } else {
+ b.WriteString("\treturn c.ReplyError(\"" + midl.Name + "." + e.Name + "\", nil)\n")
+ }
+ b.WriteString("}\n\n")
+ }
+
+ // Reply methods for all varlink methods
+ for _, m := range midl.Methods {
+ b.WriteString("func (c *VarlinkCall) Reply" + m.Name + "(")
+ for i, field := range m.Out.Fields {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(sanitizeGoName(field.Name) + " ")
+ writeType(&b, field.Type, false, 1)
+ }
+ b.WriteString(") error {\n")
+ if len(m.Out.Fields) > 0 {
+ b.WriteString("\tvar out ")
+ writeType(&b, m.Out, true, 1)
+ b.WriteString("\n")
+ for _, field := range m.Out.Fields {
+ switch field.Type.Kind {
+ case idl.TypeStruct, idl.TypeArray:
+ b.WriteString("\tout." + strings.Title(field.Name) + " = ")
+ writeType(&b, field.Type, true, 1)
+ b.WriteString("(" + sanitizeGoName(field.Name) + ")\n")
+
+ default:
+ b.WriteString("\tout." + strings.Title(field.Name) + " = " + sanitizeGoName(field.Name) + "\n")
+ }
+ }
+ b.WriteString("\treturn c.Reply(&out)\n")
+ } else {
+ b.WriteString("\treturn c.Reply(nil)\n")
+ }
+ b.WriteString("}\n\n")
+ }
+
+ // Dummy methods for all varlink methods
+ for _, m := range midl.Methods {
+ b.WriteString("func (s *VarlinkInterface) " + m.Name + "(c VarlinkCall")
+ for _, field := range m.In.Fields {
+ b.WriteString(", " + sanitizeGoName(field.Name) + " ")
+ writeType(&b, field.Type, false, 1)
+ }
+ b.WriteString(") error {\n" +
+ "\treturn c.ReplyMethodNotImplemented(\"" + m.Name + "\")\n" +
+ "}\n\n")
+ }
+
+ // Method call dispatcher
+ b.WriteString("func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error {\n" +
+ "\tswitch methodname {\n")
+ for _, m := range midl.Methods {
+ b.WriteString("\tcase \"" + m.Name + "\":\n")
+ if len(m.In.Fields) > 0 {
+ b.WriteString("\t\tvar in ")
+ writeType(&b, m.In, true, 2)
+ b.WriteString("\n")
+ b.WriteString("\t\terr := call.GetParameters(&in)\n" +
+ "\t\tif err != nil {\n" +
+ "\t\t\treturn call.ReplyInvalidParameter(\"parameters\")\n" +
+ "\t\t}\n")
+ b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call}")
+ if len(m.In.Fields) > 0 {
+ for _, field := range m.In.Fields {
+ switch field.Type.Kind {
+ case idl.TypeStruct, idl.TypeArray:
+ b.WriteString(", ")
+ writeType(&b, field.Type, false, 2)
+ b.WriteString("(in." + strings.Title(field.Name) + ")")
+
+ default:
+ b.WriteString(", in." + strings.Title(field.Name))
+ }
+ }
+ }
+ b.WriteString(")\n")
+ } else {
+ b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call})\n")
+ }
+ b.WriteString("\n")
+ }
+ b.WriteString("\tdefault:\n" +
+ "\t\treturn call.ReplyMethodNotFound(methodname)\n" +
+ "\t}\n" +
+ "}\n")
+
+ // Varlink interface name
+ b.WriteString("func (s *VarlinkInterface) VarlinkGetName() string {\n" +
+ "\treturn `" + midl.Name + "`\n" + "}\n\n")
+
+ // Varlink interface description
+ b.WriteString("func (s *VarlinkInterface) VarlinkGetDescription() string {\n" +
+ "\treturn `" + midl.Description + "\n`\n}\n\n")
+
+ b.WriteString("type VarlinkInterface struct {\n" +
+ "\t" + pkgname + "Interface\n" +
+ "}\n\n")
+
+ b.WriteString("func VarlinkNew(m " + pkgname + "Interface) *VarlinkInterface {\n" +
+ "\treturn &VarlinkInterface{m}\n" +
+ "}\n")
+
+ return pkgname, b.Bytes(), nil
+}
+
+func generateFile(varlinkFile string) {
+ file, err := ioutil.ReadFile(varlinkFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error reading file '%s': %s\n", varlinkFile, err)
+ os.Exit(1)
+ }
+
+ pkgname, b, err := generateTemplate(string(file))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error parsing file '%s': %s\n", varlinkFile, err)
+ os.Exit(1)
+ }
+
+ filename := path.Dir(varlinkFile) + "/" + pkgname + ".go"
+ err = ioutil.WriteFile(filename, b, 0660)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing file '%s': %s\n", filename, err)
+ os.Exit(1)
+ }
+}
+
+func main() {
+ if len(os.Args) != 2 {
+ fmt.Printf("Usage: %s <file>\n", os.Args[0])
+ os.Exit(1)
+ }
+ generateFile(os.Args[1])
+}
diff --git a/vendor/github.com/varlink/go/cmd/varlink-go-type-generator/main.go b/vendor/github.com/varlink/go/cmd/varlink-go-type-generator/main.go
new file mode 100644
index 000000000..dfbec5fb2
--- /dev/null
+++ b/vendor/github.com/varlink/go/cmd/varlink-go-type-generator/main.go
@@ -0,0 +1,142 @@
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/importer"
+ "go/parser"
+ "go/token"
+ "go/types"
+ "log"
+ "os"
+)
+
+func GoToVarlinkType(t types.Type) string {
+ switch u := t.(type) {
+ case *types.Basic:
+ if u.Info()&types.IsBoolean != 0 {
+ return "bool"
+ }
+ if u.Info()&types.IsInteger != 0 {
+ return "int"
+ }
+ if u.Info()&types.IsFloat != 0 {
+ return "float"
+ }
+ if u.Info()&types.IsString != 0 {
+ return "string"
+ }
+ return fmt.Sprintf("<<<%s>>>", t.String())
+
+ case *types.Named:
+ return u.Obj().Name()
+
+ case *types.Map:
+ return fmt.Sprintf("<<<%s>>>", u.String())
+
+ case *types.Interface:
+ return fmt.Sprintf("<<<%s>>>", u.String())
+
+ case *types.Pointer:
+ return fmt.Sprintf("?%s", GoToVarlinkType(u.Elem()))
+
+ case *types.Array:
+ return fmt.Sprintf("[]%s", GoToVarlinkType(u.Elem()))
+
+ case *types.Slice:
+ return fmt.Sprintf("[]%s", GoToVarlinkType(u.Elem()))
+
+ default:
+ return fmt.Sprintf("<<<%T %s>>>", t, u)
+ }
+
+ return t.String()
+}
+
+func PrintDefsUses(name string, fset *token.FileSet, files []*ast.File) error {
+ conf := types.Config{
+ Importer: importer.Default(),
+ FakeImportC: true,
+ }
+
+ info := &types.Info{
+ Defs: make(map[*ast.Ident]types.Object),
+ }
+
+ _, err := conf.Check(name, fset, files, info)
+ if err != nil {
+ return err // type error
+ }
+
+ seen := map[string]interface{}{}
+
+ for id, obj := range info.Defs {
+ if obj == nil {
+ continue
+ }
+
+ if _, ok := seen[id.Name]; ok {
+ continue
+ }
+
+ /*
+ if !obj.Exported() || obj.Pkg().Name() != name {
+ continue
+ }
+ */
+ switch f := obj.Type().Underlying().(type) {
+ case *types.Struct:
+ if f.NumFields() > 0 {
+ fmt.Printf("type %s (\n", id.Name)
+ fmt.Printf("\t%s: %s",
+ f.Field(0).Name(), GoToVarlinkType(f.Field(0).Type()))
+ for i := 1; i < f.NumFields(); i++ {
+ fmt.Printf(",\n\t%s: %s",
+ f.Field(i).Name(), GoToVarlinkType(f.Field(i).Type()))
+ }
+ fmt.Printf("\n)\n\n")
+ }
+ }
+ seen[id.Name] = nil
+ }
+
+ return nil
+}
+
+func main() {
+
+ path := os.Args[1]
+ fs := token.NewFileSet()
+
+ if stat, err := os.Stat(path); err == nil && stat.IsDir() {
+ pkgs, err := parser.ParseDir(fs, path, nil, 0)
+ if err != nil {
+ fmt.Printf("parsing dir '%s': %s", path, err)
+ }
+ for name, pkg := range pkgs {
+ log.Println("Found package:", name)
+
+ fset := make([]*ast.File, len(pkg.Files), len(pkg.Files))
+ idx := 0
+ for _, value := range pkg.Files {
+ fset[idx] = value
+ idx++
+ }
+
+ if err := PrintDefsUses(name, fs, fset); err != nil {
+ log.Print(err) // type error
+ }
+ }
+ } else {
+
+ fset, err := parser.ParseFile(fs, path, nil, 0)
+
+ if err != nil {
+ fmt.Printf("parsing file '%s': %s", path, err)
+ }
+ name := fset.Name.String()
+ if err := PrintDefsUses(name, fs, []*ast.File{fset}); err != nil {
+ log.Print(err) // type error
+ }
+ }
+}
diff --git a/vendor/github.com/varlink/go/golang-github-varlink-go.spec b/vendor/github.com/varlink/go/golang-github-varlink-go.spec
new file mode 100644
index 000000000..85f5d1788
--- /dev/null
+++ b/vendor/github.com/varlink/go/golang-github-varlink-go.spec
@@ -0,0 +1,44 @@
+%global goipath github.com/varlink/go
+Version: 0
+%gometa
+
+Name: %{goname}
+Release: 1%{?dist}
+Summary: Go bindings for varlink
+License: ASL 2.0
+URL: %{gourl}
+Source0: %{gosource}
+
+%description
+Native Go bindings for the varlink protocol.
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel
+%{summary}
+
+This package contains library source intended for
+building other packages which use import path with
+%{gobaseipath} prefix.
+
+%prep
+%forgesetup
+
+%build
+%gobuildroot
+
+%install
+gofiles=$(find . %{gofindfilter} -print)
+%goinstall $gofiles
+
+%check
+
+%files devel -f devel.file-list
+%license LICENSE
+%doc README.md
+
+%changelog
+* Tue Mar 20 2018 <info@varlink.org> 0-1
+- Version 0
diff --git a/vendor/github.com/varlink/go/varlink/call.go b/vendor/github.com/varlink/go/varlink/call.go
new file mode 100644
index 000000000..c5d7cf7fd
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/call.go
@@ -0,0 +1,86 @@
+package varlink
+
+import (
+ "bufio"
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+// Call is a method call retrieved by a Service. The connection from the
+// client can be terminated by returning an error from the call instead
+// of sending a reply or error reply.
+type Call struct {
+ writer *bufio.Writer
+ in *serviceCall
+ Continues bool
+}
+
+// WantsMore indicates if the calling client accepts more than one reply to this method call.
+func (c *Call) WantsMore() bool {
+ return c.in.More
+}
+
+// IsOneShot indicate that the calling client does not expect a reply.
+func (c *Call) IsOneShot() bool {
+ return c.in.OneShot
+}
+
+// GetParameters retrieves the method call parameters.
+func (c *Call) GetParameters(p interface{}) error {
+ if c.in.Parameters == nil {
+ return fmt.Errorf("empty parameters")
+ }
+ return json.Unmarshal(*c.in.Parameters, p)
+}
+
+func (c *Call) sendMessage(r *serviceReply) error {
+ if c.in.OneShot {
+ return nil
+ }
+
+ b, e := json.Marshal(r)
+ if e != nil {
+ return e
+ }
+
+ b = append(b, 0)
+ _, e = c.writer.Write(b)
+ if e != nil {
+ return e
+ }
+ return c.writer.Flush()
+}
+
+// Reply sends a reply to this method call.
+func (c *Call) Reply(parameters interface{}) error {
+ if !c.Continues {
+ return c.sendMessage(&serviceReply{
+ Parameters: parameters,
+ })
+ }
+
+ if !c.in.More {
+ return fmt.Errorf("call did not set more, it does not expect continues")
+ }
+
+ return c.sendMessage(&serviceReply{
+ Continues: true,
+ Parameters: parameters,
+ })
+}
+
+// ReplyError sends an error reply to this method call.
+func (c *Call) ReplyError(name string, parameters interface{}) error {
+ r := strings.LastIndex(name, ".")
+ if r <= 0 {
+ return fmt.Errorf("invalid error name")
+ }
+ if name[:r] == "org.varlink.service" {
+ return fmt.Errorf("refused to send org.varlink.service errors")
+ }
+ return c.sendMessage(&serviceReply{
+ Error: name,
+ Parameters: parameters,
+ })
+}
diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go
new file mode 100644
index 000000000..2445072b6
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/connection.go
@@ -0,0 +1,197 @@
+package varlink
+
+import (
+ "bufio"
+ "encoding/json"
+ "net"
+ "strings"
+)
+
+// Error is a varlink error returned from a method call.
+type Error struct {
+ Name string
+ Parameters interface{}
+}
+
+// Error returns the fully-qualified varlink error name.
+func (e *Error) Error() string {
+ return e.Name
+}
+
+// Connection is a connection from a client to a service.
+type Connection struct {
+ address string
+ conn net.Conn
+ reader *bufio.Reader
+ writer *bufio.Writer
+}
+
+// Send sends a method call.
+func (c *Connection) Send(method string, parameters interface{}, more bool) error {
+ type call struct {
+ Method string `json:"method"`
+ Parameters interface{} `json:"parameters,omitempty"`
+ More bool `json:"more,omitempty"`
+ OneShot bool `json:"oneshot,omitempty"`
+ }
+ m := call{
+ Method: method,
+ Parameters: parameters,
+ More: more,
+ }
+ b, err := json.Marshal(m)
+ if err != nil {
+ return err
+ }
+
+ b = append(b, 0)
+ _, err = c.writer.Write(b)
+ if err != nil {
+ return err
+ }
+
+ return c.writer.Flush()
+}
+
+// Receive receives a method reply.
+func (c *Connection) Receive(parameters interface{}, continues *bool, oneshot *bool) error {
+ type reply struct {
+ Parameters *json.RawMessage `json:"parameters"`
+ Continues bool `json:"continues"`
+ Oneshot bool `json:"oneshot"`
+ Error string `json:"error"`
+ }
+
+ out, err := c.reader.ReadBytes('\x00')
+ if err != nil {
+ return err
+ }
+
+ var m reply
+ err = json.Unmarshal(out[:len(out)-1], &m)
+ if err != nil {
+ return err
+ }
+
+ if m.Error != "" {
+ return &Error{
+ Name: m.Error,
+ Parameters: m.Parameters,
+ }
+ }
+
+ if continues != nil {
+ *continues = m.Continues
+ }
+ if oneshot != nil {
+ *oneshot = m.Oneshot
+ }
+ if parameters != nil && m.Parameters != nil {
+ return json.Unmarshal(*m.Parameters, parameters)
+ }
+
+ return nil
+}
+
+// Call sends a method call and returns the result of the call.
+func (c *Connection) Call(method string, parameters interface{}, result interface{}) error {
+ err := c.Send(method, &parameters, false)
+ if err != nil {
+ return err
+ }
+
+ return c.Receive(result, nil, nil)
+}
+
+// GetInterfaceDescription requests the interface description string from the service.
+func (c *Connection) GetInterfaceDescription(name string) (string, error) {
+ type request struct {
+ Interface string `json:"interface"`
+ }
+ type reply struct {
+ Description string `json:"description"`
+ }
+
+ var r reply
+ err := c.Call("org.varlink.service.GetInterfaceDescription", request{Interface: name}, &r)
+ if err != nil {
+ return "", err
+ }
+
+ return r.Description, nil
+}
+
+// GetInfo requests information about the service.
+func (c *Connection) GetInfo(vendor *string, product *string, version *string, url *string, interfaces *[]string) error {
+ type reply struct {
+ Vendor string `json:"vendor"`
+ Product string `json:"product"`
+ Version string `json:"version"`
+ URL string `json:"url"`
+ Interfaces []string `json:"interfaces"`
+ }
+
+ var r reply
+ err := c.Call("org.varlink.service.GetInfo", nil, &r)
+ if err != nil {
+ return err
+ }
+
+ if vendor != nil {
+ *vendor = r.Vendor
+ }
+ if product != nil {
+ *product = r.Product
+ }
+ if version != nil {
+ *version = r.Version
+ }
+ if url != nil {
+ *url = r.URL
+ }
+ if interfaces != nil {
+ *interfaces = r.Interfaces
+ }
+
+ return nil
+}
+
+// Close terminates the connection.
+func (c *Connection) Close() error {
+ return c.conn.Close()
+}
+
+// NewConnection returns a new connection to the given address.
+func NewConnection(address string) (*Connection, error) {
+ var err error
+
+ words := strings.SplitN(address, ":", 2)
+ protocol := words[0]
+ addr := words[1]
+
+ // Ignore parameters after ';'
+ words = strings.SplitN(addr, ";", 2)
+ if words != nil {
+ addr = words[0]
+ }
+
+ switch protocol {
+ case "unix":
+ break
+
+ case "tcp":
+ break
+ }
+
+ c := Connection{}
+ c.conn, err = net.Dial(protocol, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ c.address = address
+ c.reader = bufio.NewReader(c.conn)
+ c.writer = bufio.NewWriter(c.conn)
+
+ return &c, nil
+}
diff --git a/vendor/github.com/varlink/go/varlink/doc.go b/vendor/github.com/varlink/go/varlink/doc.go
new file mode 100644
index 000000000..de1ed2380
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/doc.go
@@ -0,0 +1,63 @@
+/*
+Package varlink provides varlink client and server implementations. See http://varlink.org
+for more information about varlink.
+
+Example varlink interface definition in a org.example.this.varlink file:
+ interface org.example.this
+
+ method Ping(in: string) -> (out: string)
+
+Generated Go module in a orgexamplethis/orgexamplethis.go file. The generated module
+provides reply methods for all methods specified in the varlink interface description.
+The stub implementations return a MethodNotImplemented error; the service implementation
+using this module will override the methods with its own implementation.
+ // Generated with github.com/varlink/go/cmd/varlink-go-interface-generator
+ package orgexamplethis
+
+ import "github.com/varlink/go/varlink"
+
+ type orgexamplethisInterface interface {
+ Ping(c VarlinkCall, in string) error
+ }
+
+ type VarlinkCall struct{ varlink.Call }
+
+ func (c *VarlinkCall) ReplyPing(out string) error {
+ var out struct {
+ Out string `json:"out,omitempty"`
+ }
+ out.Out = out
+ return c.Reply(&out)
+ }
+
+ func (s *VarlinkInterface) Ping(c VarlinkCall, in string) error {
+ return c.ReplyMethodNotImplemented("Ping")
+ }
+
+ [...]
+
+Service implementing the interface and its method:
+ import ("orgexamplethis")
+
+ type Data struct {
+ orgexamplethis.VarlinkInterface
+ data string
+ }
+
+ data := Data{data: "test"}
+
+ func (d *Data) Ping(call orgexamplethis.VarlinkCall, ping string) error {
+ return call.ReplyPing(ping)
+ }
+
+ service, _ = varlink.NewService(
+ "Example",
+ "This",
+ "1",
+ "https://example.org/this",
+ )
+
+ service.RegisterInterface(orgexamplethis.VarlinkNew(&data))
+ err := service.Listen("unix:/run/org.example.this", 0)
+*/
+package varlink
diff --git a/vendor/github.com/varlink/go/varlink/external_test.go b/vendor/github.com/varlink/go/varlink/external_test.go
new file mode 100644
index 000000000..dbe4290e6
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/external_test.go
@@ -0,0 +1,144 @@
+package varlink_test
+
+// test with no internal access
+
+import (
+ "github.com/varlink/go/varlink"
+ "os"
+ "testing"
+ "time"
+)
+
+type VarlinkInterface struct{}
+
+func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error {
+ return call.ReplyMethodNotImplemented(methodname)
+}
+func (s *VarlinkInterface) VarlinkGetName() string {
+ return `org.example.test`
+}
+
+func (s *VarlinkInterface) VarlinkGetDescription() string {
+ return "#"
+}
+
+type VarlinkInterface2 struct{}
+
+func (s *VarlinkInterface2) VarlinkDispatch(call varlink.Call, methodname string) error {
+ return call.ReplyMethodNotImplemented(methodname)
+}
+func (s *VarlinkInterface2) VarlinkGetName() string {
+ return `org.example.test2`
+}
+
+func (s *VarlinkInterface2) VarlinkGetDescription() string {
+ return "#"
+}
+
+func TestRegisterService(t *testing.T) {
+ newTestInterface := new(VarlinkInterface)
+ service, err := varlink.NewService(
+ "Varlink",
+ "Varlink Test",
+ "1",
+ "https://github.com/varlink/go/varlink",
+ )
+ if err != nil {
+ t.Fatalf("NewService(): %v", err)
+ }
+
+ if err := service.RegisterInterface(newTestInterface); err != nil {
+ t.Fatalf("Couldn't register service: %v", err)
+ }
+
+ if err := service.RegisterInterface(newTestInterface); err == nil {
+ t.Fatal("Could register service twice")
+ }
+
+ defer func() { service.Shutdown() }()
+
+ servererror := make(chan error)
+
+ go func() {
+ servererror <- service.Listen("unix:@varlinkexternal_TestRegisterService", 0)
+ }()
+
+ time.Sleep(time.Second / 5)
+
+ n := new(VarlinkInterface2)
+
+ if err := service.RegisterInterface(n); err == nil {
+ t.Fatal("Could register service while running")
+ }
+ time.Sleep(time.Second / 5)
+ service.Shutdown()
+
+ if err := <-servererror; err != nil {
+ t.Fatalf("service.Listen(): %v", err)
+ }
+}
+
+func TestUnix(t *testing.T) {
+ newTestInterface := new(VarlinkInterface)
+ service, err := varlink.NewService(
+ "Varlink",
+ "Varlink Test",
+ "1",
+ "https://github.com/varlink/go/varlink",
+ )
+
+ if err != nil {
+ t.Fatalf("NewService(): %v", err)
+ }
+
+ if err := service.RegisterInterface(newTestInterface); err != nil {
+ t.Fatalf("RegisterInterface(): %v", err)
+ }
+
+ servererror := make(chan error)
+
+ go func() {
+ servererror <- service.Listen("unix:varlinkexternal_TestUnix", 0)
+ }()
+
+ time.Sleep(time.Second / 5)
+ service.Shutdown()
+
+ if err := <-servererror; err != nil {
+ t.Fatalf("service.Listen(): %v", err)
+ }
+}
+
+func TestListenFDSNotInt(t *testing.T) {
+ newTestInterface := new(VarlinkInterface)
+ service, err := varlink.NewService(
+ "Varlink",
+ "Varlink Test",
+ "1",
+ "https://github.com/varlink/go/varlink",
+ )
+
+ if err != nil {
+ t.Fatalf("NewService(): %v", err)
+ }
+
+ if err := service.RegisterInterface(newTestInterface); err != nil {
+ t.Fatalf("Couldn't register service: %v", err)
+ }
+ os.Setenv("LISTEN_FDS", "foo")
+
+ servererror := make(chan error)
+
+ go func() {
+ servererror <- service.Listen("unix:varlinkexternal_TestListenFDSNotInt", 0)
+ }()
+
+ time.Sleep(time.Second / 5)
+ service.Shutdown()
+
+ err = <-servererror
+
+ if err != nil {
+ t.Fatalf("service.Run(): %v", err)
+ }
+}
diff --git a/vendor/github.com/varlink/go/varlink/idl/idl.go b/vendor/github.com/varlink/go/varlink/idl/idl.go
new file mode 100644
index 000000000..27f21a759
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/idl/idl.go
@@ -0,0 +1,465 @@
+// Package idl provides a varlink interface description parser.
+package idl
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+)
+
+// Valid TypeKind values.
+const (
+ TypeBool = iota
+ TypeInt
+ TypeFloat
+ TypeString
+ TypeArray
+ TypeMaybe
+ TypeStruct
+ TypeEnum
+ TypeAlias
+)
+
+// TypeKind specifies the type of an Type.
+type TypeKind uint
+
+// Type represents a varlink type. Types are method input and output parameters,
+// error output parameters, or custom defined types in the interface description.
+type Type struct {
+ Kind TypeKind
+ ElementType *Type
+ Alias string
+ Fields []TypeField
+}
+
+// TypeField is a named member of a TypeStruct.
+type TypeField struct {
+ Name string
+ Type *Type
+}
+
+// Alias represents a named Type in the interface description.
+type Alias struct {
+ Name string
+ Doc string
+ Type *Type
+}
+
+// Method represents a method defined in the interface description.
+type Method struct {
+ Name string
+ Doc string
+ In *Type
+ Out *Type
+}
+
+// Error represents an error defined in the interface description.
+type Error struct {
+ Name string
+ Type *Type
+}
+
+// IDL represents a parsed varlink interface description with types, methods, errors and
+// documentation.
+type IDL struct {
+ Name string
+ Doc string
+ Description string
+ Members []interface{}
+ Aliases map[string]*Alias
+ Methods map[string]*Method
+ Errors map[string]*Error
+}
+
+type parser struct {
+ input string
+ position int
+ lineStart int
+ lastComment bytes.Buffer
+}
+
+func (p *parser) next() int {
+ r := -1
+
+ if p.position < len(p.input) {
+ r = int(p.input[p.position])
+ }
+
+ p.position++
+ return r
+}
+
+func (p *parser) backup() {
+ p.position--
+}
+
+func (p *parser) advance() bool {
+ for {
+ char := p.next()
+
+ if char == '\n' {
+ p.lineStart = p.position
+ p.lastComment.Reset()
+
+ } else if char == ' ' || char == '\t' {
+ // ignore
+
+ } else if char == '#' {
+ p.next()
+ start := p.position
+ for {
+ c := p.next()
+ if c < 0 || c == '\n' {
+ p.backup()
+ break
+ }
+ }
+ if p.lastComment.Len() > 0 {
+ p.lastComment.WriteByte('\n')
+ }
+ p.lastComment.WriteString(p.input[start:p.position])
+ p.next()
+
+ } else {
+ p.backup()
+ break
+ }
+ }
+
+ return p.position < len(p.input)
+}
+
+func (p *parser) advanceOnLine() {
+ for {
+ char := p.next()
+ if char != ' ' {
+ p.backup()
+ return
+ }
+ }
+}
+
+func (p *parser) readKeyword() string {
+ start := p.position
+
+ for {
+ char := p.next()
+ if char < 'a' || char > 'z' {
+ p.backup()
+ break
+ }
+ }
+
+ return p.input[start:p.position]
+}
+
+func (p *parser) readInterfaceName() string {
+ start := p.position
+ dnrx := regexp.MustCompile(`^[a-z]+(\.[a-z0-9]+([-][a-z0-9]+)*)+`)
+ name := dnrx.FindString(p.input[start:])
+ if name != "" {
+ if len(name) > 255 {
+ return ""
+ }
+ p.position += len(name)
+ return name
+ }
+ xdnrx := regexp.MustCompile(`^xn--[a-z0-9]+(\.[a-z0-9]+([-][a-z0-9]+)*)+`)
+ name = xdnrx.FindString(p.input[start:])
+ if name != "" {
+ if len(name) > 255 {
+ return ""
+ }
+ p.position += len(name)
+ return name
+ }
+ return ""
+}
+
+func (p *parser) readFieldName() string {
+ start := p.position
+
+ char := p.next()
+ if char < 'a' || char > 'z' {
+ p.backup()
+ return ""
+ }
+
+ for {
+ char := p.next()
+ if (char < 'A' || char > 'Z') && (char < 'a' || char > 'z') && (char < '0' || char > '9') && char != '_' {
+ p.backup()
+ break
+ }
+ }
+
+ return p.input[start:p.position]
+}
+
+func (p *parser) readTypeName() string {
+ start := p.position
+
+ for {
+ char := p.next()
+ if (char < 'A' || char > 'Z') && (char < 'a' || char > 'z') && (char < '0' || char > '9') {
+ p.backup()
+ break
+ }
+ }
+
+ return p.input[start:p.position]
+}
+
+func (p *parser) readStructType() *Type {
+ if p.next() != '(' {
+ p.backup()
+ return nil
+ }
+
+ t := &Type{Kind: TypeStruct}
+ t.Fields = make([]TypeField, 0)
+
+ char := p.next()
+ if char != ')' {
+ p.backup()
+
+ for {
+ field := TypeField{}
+
+ p.advance()
+ field.Name = p.readFieldName()
+ if field.Name == "" {
+ return nil
+ }
+
+ p.advance()
+
+ // Enums have no types, they are just a list of names
+ if p.next() == ':' {
+ if t.Kind == TypeEnum {
+ return nil
+ }
+
+ p.advance()
+ field.Type = p.readType()
+ if field.Type == nil {
+ return nil
+ }
+
+ } else {
+ t.Kind = TypeEnum
+ p.backup()
+ }
+
+ t.Fields = append(t.Fields, field)
+
+ p.advance()
+ char = p.next()
+ if char != ',' {
+ break
+ }
+ }
+
+ if char != ')' {
+ return nil
+ }
+ }
+
+ return t
+}
+
+func (p *parser) readType() *Type {
+ var t *Type
+
+ switch p.next() {
+ case '?':
+ e := p.readType()
+ if e == nil {
+ return nil
+ }
+ t = &Type{Kind: TypeMaybe, ElementType: e}
+
+ case '[':
+ if p.next() != ']' {
+ return nil
+ }
+ e := p.readType()
+ if e == nil {
+ return nil
+ }
+ t = &Type{Kind: TypeArray, ElementType: e}
+
+ default:
+ p.backup()
+ if keyword := p.readKeyword(); keyword != "" {
+ switch keyword {
+ case "bool":
+ t = &Type{Kind: TypeBool}
+
+ case "int":
+ t = &Type{Kind: TypeInt}
+
+ case "float":
+ t = &Type{Kind: TypeFloat}
+
+ case "string":
+ t = &Type{Kind: TypeString}
+ }
+
+ } else if name := p.readTypeName(); name != "" {
+ t = &Type{Kind: TypeAlias, Alias: name}
+
+ } else if t = p.readStructType(); t == nil {
+ return nil
+ }
+ }
+
+ return t
+}
+
+func (p *parser) readAlias(idl *IDL) (*Alias, error) {
+ a := &Alias{}
+
+ p.advance()
+ a.Doc = p.lastComment.String()
+ a.Name = p.readTypeName()
+ if a.Name == "" {
+ return nil, fmt.Errorf("missing type name")
+ }
+
+ p.advance()
+ a.Type = p.readType()
+ if a.Type == nil {
+ return nil, fmt.Errorf("missing type declaration")
+ }
+
+ return a, nil
+}
+
+func (p *parser) readMethod(idl *IDL) (*Method, error) {
+ m := &Method{}
+
+ p.advance()
+ m.Doc = p.lastComment.String()
+ m.Name = p.readTypeName()
+ if m.Name == "" {
+ return nil, fmt.Errorf("missing method type")
+ }
+
+ p.advance()
+ m.In = p.readType()
+ if m.In == nil {
+ return nil, fmt.Errorf("missing method input")
+ }
+
+ p.advance()
+ one := p.next()
+ two := p.next()
+ if (one != '-') || two != '>' {
+ return nil, fmt.Errorf("missing method '->' operator")
+ }
+
+ p.advance()
+ m.Out = p.readType()
+ if m.Out == nil {
+ return nil, fmt.Errorf("missing method output")
+ }
+
+ return m, nil
+}
+
+func (p *parser) readError(idl *IDL) (*Error, error) {
+ e := &Error{}
+
+ p.advance()
+ e.Name = p.readTypeName()
+ if e.Name == "" {
+ return nil, fmt.Errorf("missing error name")
+ }
+
+ p.advanceOnLine()
+ e.Type = p.readType()
+
+ return e, nil
+}
+
+func (p *parser) readIDL() (*IDL, error) {
+ if keyword := p.readKeyword(); keyword != "interface" {
+ return nil, fmt.Errorf("missing interface keyword")
+ }
+
+ idl := &IDL{
+ Members: make([]interface{}, 0),
+ Aliases: make(map[string]*Alias),
+ Methods: make(map[string]*Method),
+ Errors: make(map[string]*Error),
+ }
+
+ p.advance()
+ idl.Doc = p.lastComment.String()
+ idl.Name = p.readInterfaceName()
+ if idl.Name == "" {
+ return nil, fmt.Errorf("interface name")
+ }
+
+ for {
+ if !p.advance() {
+ break
+ }
+
+ switch keyword := p.readKeyword(); keyword {
+ case "type":
+ a, err := p.readAlias(idl)
+ if err != nil {
+ return nil, err
+ }
+
+ idl.Members = append(idl.Members, a)
+ idl.Aliases[a.Name] = a
+
+ case "method":
+ m, err := p.readMethod(idl)
+ if err != nil {
+ return nil, err
+ }
+
+ idl.Members = append(idl.Members, m)
+ if _, ok := idl.Methods[m.Name]; ok {
+ return nil, fmt.Errorf("method `%s` already defined", m.Name)
+ }
+ idl.Methods[m.Name] = m
+
+ case "error":
+ e, err := p.readError(idl)
+ if err != nil {
+ return nil, err
+ }
+
+ idl.Members = append(idl.Members, e)
+ idl.Errors[e.Name] = e
+
+ default:
+ return nil, fmt.Errorf("unknown keyword '%s'", keyword)
+ }
+ }
+
+ return idl, nil
+}
+
+// New parses a varlink interface description.
+func New(description string) (*IDL, error) {
+ p := &parser{input: description}
+
+ p.advance()
+ idl, err := p.readIDL()
+ if err != nil {
+ return nil, err
+ }
+
+ if len(idl.Methods) == 0 {
+ return nil, fmt.Errorf("no methods defined")
+ }
+
+ idl.Description = description
+ return idl, nil
+}
diff --git a/vendor/github.com/varlink/go/varlink/idl/idl_test.go b/vendor/github.com/varlink/go/varlink/idl/idl_test.go
new file mode 100644
index 000000000..5d83d5890
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/idl/idl_test.go
@@ -0,0 +1,127 @@
+package idl
+
+import (
+ "fmt"
+ "runtime"
+ "testing"
+)
+
+/*
+func expect(t *testing.T, expected string, returned string) {
+ if strings.Compare(returned, expected) != 0 {
+ t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
+ len(expected), expected,
+ len(returned), returned)
+ }
+}
+*/
+
+func testParse(t *testing.T, pass bool, description string) {
+ _, _, line, _ := runtime.Caller(1)
+
+ t.Run(fmt.Sprintf("Line-%d", line), func(t *testing.T) {
+ midl, err := New(description)
+ if pass {
+ if err != nil {
+ t.Fatalf("generateTemplate(`%s`): %v", description, err)
+ }
+ if len(midl.Name) <= 0 {
+ t.Fatalf("generateTemplate(`%s`): returned no pkgname", description)
+ }
+ }
+ if !pass && (err == nil) {
+ t.Fatalf("generateTemplate(`%s`): did not fail", description)
+ }
+ })
+}
+
+func TestOneMethod(t *testing.T) {
+ testParse(t, true, "interface foo.bar\nmethod Foo()->()")
+}
+
+func TestOneMethodNoType(t *testing.T) {
+ testParse(t, false, "interface foo.bar\nmethod Foo()->(b:)")
+}
+
+func TestDomainNames(t *testing.T) {
+ testParse(t, true, "interface org.varlink.service\nmethod F()->()")
+ testParse(t, true, "interface com.example.0example\nmethod F()->()")
+ testParse(t, true, "interface com.example.example-dash\nmethod F()->()")
+ testParse(t, true, "interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()")
+ testParse(t, false, "interface com.-example.leadinghyphen\nmethod F()->()")
+ testParse(t, false, "interface com.example-.danglinghyphen-\nmethod F()->()")
+ testParse(t, false, "interface Com.example.uppercase-toplevel\nmethod F()->()")
+ testParse(t, false, "interface Co9.example.number-toplevel\nmethod F()->()")
+ testParse(t, false, "interface 1om.example.number-toplevel\nmethod F()->()")
+ testParse(t, false, "interface com.Example\nmethod F()->()")
+ var name string
+ for i := 0; i < 255; i++ {
+ name += "a"
+ }
+ testParse(t, false, "interface com.example.toolong"+name+"\nmethod F()->()")
+ testParse(t, false, "interface xn--example.toolong"+name+"\nmethod F()->()")
+}
+
+func TestNoMethod(t *testing.T) {
+ testParse(t, false, `
+interface org.varlink.service
+ type Interface (name: string, types: []Type, methods: []Method)
+ type Property (key: string, value: string)
+`)
+}
+
+func TestTypeNoArgs(t *testing.T) {
+ testParse(t, true, "interface foo.bar\n type I ()\nmethod F()->()")
+}
+
+func TestTypeOneArg(t *testing.T) {
+ testParse(t, true, "interface foo.bar\n type I (b:bool)\nmethod F()->()")
+}
+
+func TestTypeOneArray(t *testing.T) {
+ testParse(t, true, "interface foo.bar\n type I (b:[]bool)\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (b:bool[ ])\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (b:bool[1])\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (b:bool[ 1 ])\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (b:bool[ 1 1 ])\nmethod F()->()")
+}
+
+func TestFieldnames(t *testing.T) {
+ testParse(t, false, "interface foo.bar\n type I (Test:[]bool)\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (_test:[]bool)\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (Ă„est:[]bool)\nmethod F()->()")
+}
+func TestNestedStructs(t *testing.T) {
+ testParse(t, true, "interface foo.bar\n type I ( b: [](foo: bool, bar: bool, baz: int) )\nmethod F()->()")
+}
+
+func TestEnum(t *testing.T) {
+ testParse(t, true, "interface foo.bar\n type I (b:(foo, bar, baz))\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\n type I (foo, bar, baz : bool)\nmethod F()->()")
+}
+
+func TestIncomplete(t *testing.T) {
+ testParse(t, false, "interfacef foo.bar\nmethod F()->()")
+ testParse(t, false, "interface foo.bar\nmethod F()->()\ntype I (b: bool")
+ testParse(t, false, "interface foo.bar\nmethod F()->(")
+ testParse(t, false, "interface foo.bar\nmethod F(")
+ testParse(t, false, "interface foo.bar\nmethod ()->()")
+ testParse(t, false, "interface foo.bar\nmethod F->()\n")
+ testParse(t, false, "interface foo.bar\nmethod F()->\n")
+ testParse(t, false, "interface foo.bar\nmethod F()>()\n")
+ testParse(t, false, "interface foo.bar\nmethod F()->()\ntype (b: bool)")
+ testParse(t, false, "interface foo.bar\nmethod F()->()\nerror (b: bool)")
+ testParse(t, false, "interface foo.bar\nmethod F()->()\n dfghdrg")
+}
+
+func TestDuplicate(t *testing.T) {
+ testParse(t, false, `
+interface foo.example
+ type Device()
+ type Device()
+ type T()
+ type T()
+ method F() -> ()
+ method F() -> ()
+`)
+}
diff --git a/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go b/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
new file mode 100644
index 000000000..39f843c31
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
@@ -0,0 +1,133 @@
+package varlink
+
+func doReplyError(c *Call, name string, parameters interface{}) error {
+ return c.sendMessage(&serviceReply{
+ Error: name,
+ Parameters: parameters,
+ })
+}
+
+// ReplyInterfaceNotFound sends a org.varlink.service errror reply to this method call
+func (c *Call) ReplyInterfaceNotFound(interfaceA string) error {
+ var out struct {
+ Interface string `json:"interface,omitempty"`
+ }
+ out.Interface = interfaceA
+ return doReplyError(c, "org.varlink.service.InterfaceNotFound", &out)
+}
+
+// ReplyMethodNotFound sends a org.varlink.service errror reply to this method call
+func (c *Call) ReplyMethodNotFound(method string) error {
+ var out struct {
+ Method string `json:"method,omitempty"`
+ }
+ out.Method = method
+ return doReplyError(c, "org.varlink.service.MethodNotFound", &out)
+}
+
+// ReplyMethodNotImplemented sends a org.varlink.service errror reply to this method call
+func (c *Call) ReplyMethodNotImplemented(method string) error {
+ var out struct {
+ Method string `json:"method,omitempty"`
+ }
+ out.Method = method
+ return doReplyError(c, "org.varlink.service.MethodNotImplemented", &out)
+}
+
+// ReplyInvalidParameter sends a org.varlink.service errror reply to this method call
+func (c *Call) ReplyInvalidParameter(parameter string) error {
+ var out struct {
+ Parameter string `json:"parameter,omitempty"`
+ }
+ out.Parameter = parameter
+ return doReplyError(c, "org.varlink.service.InvalidParameter", &out)
+}
+
+func (c *Call) replyGetInfo(vendor string, product string, version string, url string, interfaces []string) error {
+ var out struct {
+ Vendor string `json:"vendor,omitempty"`
+ Product string `json:"product,omitempty"`
+ Version string `json:"version,omitempty"`
+ URL string `json:"url,omitempty"`
+ Interfaces []string `json:"interfaces,omitempty"`
+ }
+ out.Vendor = vendor
+ out.Product = product
+ out.Version = version
+ out.URL = url
+ out.Interfaces = interfaces
+ return c.Reply(&out)
+}
+
+func (c *Call) replyGetInterfaceDescription(description string) error {
+ var out struct {
+ Description string `json:"description,omitempty"`
+ }
+ out.Description = description
+ return c.Reply(&out)
+}
+
+func (s *Service) orgvarlinkserviceDispatch(c Call, methodname string) error {
+ switch methodname {
+ case "GetInfo":
+ return s.getInfo(c)
+ case "GetInterfaceDescription":
+ var in struct {
+ Interface string `json:"interface"`
+ }
+ err := c.GetParameters(&in)
+ if err != nil {
+ return c.ReplyInvalidParameter("parameters")
+ }
+ return s.getInterfaceDescription(c, in.Interface)
+
+ default:
+ return c.ReplyMethodNotFound(methodname)
+ }
+}
+
+func (s *orgvarlinkserviceInterface) VarlinkDispatch(call Call, methodname string) error {
+ return nil
+}
+
+func (s *orgvarlinkserviceInterface) VarlinkGetName() string {
+ return `org.varlink.service`
+}
+
+func (s *orgvarlinkserviceInterface) VarlinkGetDescription() string {
+ return `# The Varlink Service Interface is provided by every varlink service. It
+# describes the service and the interfaces it implements.
+interface org.varlink.service
+
+# Get a list of all the interfaces a service provides and information
+# about the implementation.
+method GetInfo() -> (
+ vendor: string,
+ product: string,
+ version: string,
+ url: string,
+ interfaces: []string
+)
+
+# Get the description of an interface that is implemented by this service.
+method GetInterfaceDescription(interface: string) -> (description: string)
+
+# The requested interface was not found.
+error InterfaceNotFound (interface: string)
+
+# The requested method was not found
+error MethodNotFound (method: string)
+
+# The interface defines the requested method, but the service does not
+# implement it.
+error MethodNotImplemented (method: string)
+
+# One of the passed parameters is invalid.
+error InvalidParameter (parameter: string)`
+}
+
+type orgvarlinkserviceInterface struct{}
+
+func orgvarlinkserviceNew() *orgvarlinkserviceInterface {
+ return &orgvarlinkserviceInterface{}
+}
diff --git a/vendor/github.com/varlink/go/varlink/resolver.go b/vendor/github.com/varlink/go/varlink/resolver.go
new file mode 100644
index 000000000..f0f4487d2
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/resolver.go
@@ -0,0 +1,92 @@
+package varlink
+
+// ResolverAddress is the well-known address of the varlink interface resolver,
+// it translates varlink interface names to varlink service addresses.
+const ResolverAddress = "unix:/run/org.varlink.resolver"
+
+// Resolver resolves varlink interface names to varlink addresses
+type Resolver struct {
+ address string
+ conn *Connection
+}
+
+// Resolve resolves a varlink interface name to a varlink address.
+func (r *Resolver) Resolve(iface string) (string, error) {
+ type request struct {
+ Interface string `json:"interface"`
+ }
+ type reply struct {
+ Address string `json:"address"`
+ }
+
+ /* don't ask the resolver for itself */
+ if iface == "org.varlink.resolver" {
+ return r.address, nil
+ }
+
+ var rep reply
+ err := r.conn.Call("org.varlink.resolver.Resolve", &request{Interface: iface}, &rep)
+ if err != nil {
+ return "", err
+ }
+
+ return rep.Address, nil
+}
+
+// GetInfo requests information about the resolver.
+func (r *Resolver) GetInfo(vendor *string, product *string, version *string, url *string, interfaces *[]string) error {
+ type reply struct {
+ Vendor string
+ Product string
+ Version string
+ URL string
+ Interfaces []string
+ }
+
+ var rep reply
+ err := r.conn.Call("org.varlink.resolver.GetInfo", nil, &rep)
+ if err != nil {
+ return err
+ }
+
+ if vendor != nil {
+ *vendor = rep.Vendor
+ }
+ if product != nil {
+ *product = rep.Product
+ }
+ if version != nil {
+ *version = rep.Version
+ }
+ if url != nil {
+ *url = rep.URL
+ }
+ if interfaces != nil {
+ *interfaces = rep.Interfaces
+ }
+
+ return nil
+}
+
+// Close terminates the resolver.
+func (r *Resolver) Close() error {
+ return r.conn.Close()
+}
+
+// NewResolver returns a new resolver connected to the given address.
+func NewResolver(address string) (*Resolver, error) {
+ if address == "" {
+ address = ResolverAddress
+ }
+
+ c, err := NewConnection(address)
+ if err != nil {
+ return nil, err
+ }
+ r := Resolver{
+ address: address,
+ conn: c,
+ }
+
+ return &r, nil
+}
diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go
new file mode 100644
index 000000000..eb110e503
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/service.go
@@ -0,0 +1,350 @@
+package varlink
+
+import (
+ "bufio"
+ "encoding/json"
+ "fmt"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+)
+
+type dispatcher interface {
+ VarlinkDispatch(c Call, methodname string) error
+ VarlinkGetName() string
+ VarlinkGetDescription() string
+}
+
+type serviceCall struct {
+ Method string `json:"method"`
+ Parameters *json.RawMessage `json:"parameters,omitempty"`
+ More bool `json:"more,omitempty"`
+ OneShot bool `json:"oneshot,omitempty"`
+}
+
+type serviceReply struct {
+ Parameters interface{} `json:"parameters,omitempty"`
+ Continues bool `json:"continues,omitempty"`
+ Error string `json:"error,omitempty"`
+}
+
+// Service represents an active varlink service. In addition to the registered custom varlink Interfaces, every service
+// implements the org.varlink.service interface which allows clients to retrieve information about the
+// running service.
+type Service struct {
+ vendor string
+ product string
+ version string
+ url string
+ interfaces map[string]dispatcher
+ names []string
+ descriptions map[string]string
+ running bool
+ listener net.Listener
+ conncounter int64
+ mutex sync.Mutex
+ protocol string
+ address string
+}
+
+func (s *Service) getInfo(c Call) error {
+ return c.replyGetInfo(s.vendor, s.product, s.version, s.url, s.names)
+}
+
+func (s *Service) getInterfaceDescription(c Call, name string) error {
+ if name == "" {
+ return c.ReplyInvalidParameter("interface")
+ }
+
+ description, ok := s.descriptions[name]
+ if !ok {
+ return c.ReplyInvalidParameter("interface")
+ }
+
+ return c.replyGetInterfaceDescription(description)
+}
+
+func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
+ var in serviceCall
+
+ err := json.Unmarshal(request, &in)
+
+ if err != nil {
+ return err
+ }
+
+ c := Call{
+ writer: writer,
+ in: &in,
+ }
+
+ r := strings.LastIndex(in.Method, ".")
+ if r <= 0 {
+ return c.ReplyInvalidParameter("method")
+ }
+
+ interfacename := in.Method[:r]
+ methodname := in.Method[r+1:]
+
+ if interfacename == "org.varlink.service" {
+ return s.orgvarlinkserviceDispatch(c, methodname)
+ }
+
+ // Find the interface and method in our service
+ iface, ok := s.interfaces[interfacename]
+ if !ok {
+ return c.ReplyInterfaceNotFound(interfacename)
+ }
+
+ return iface.VarlinkDispatch(c, methodname)
+}
+
+func activationListener() net.Listener {
+ pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
+ if err != nil || pid != os.Getpid() {
+ return nil
+ }
+
+ nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
+ if err != nil || nfds < 1 {
+ return nil
+ }
+
+ fd := -1
+
+ // If more than one file descriptor is passed, find the
+ // "varlink" tag. The first file descriptor is always 3.
+ if nfds > 1 {
+ fdnames, set := os.LookupEnv("LISTEN_FDNAMES")
+ if !set {
+ return nil
+ }
+
+ names := strings.Split(fdnames, ":")
+ if len(names) != nfds {
+ return nil
+ }
+
+ for i, name := range names {
+ if name == "varlink" {
+ fd = 3 + i
+ break
+ }
+ }
+
+ if fd < 0 {
+ return nil
+ }
+
+ } else {
+ fd = 3
+ }
+
+ syscall.CloseOnExec(fd)
+
+ file := os.NewFile(uintptr(fd), "varlink")
+ listener, err := net.FileListener(file)
+ if err != nil {
+ return nil
+ }
+
+ os.Unsetenv("LISTEN_PID")
+ os.Unsetenv("LISTEN_FDS")
+ os.Unsetenv("LISTEN_FDNAMES")
+
+ return listener
+}
+
+// Shutdown shuts down the listener of a running service.
+func (s *Service) Shutdown() {
+ s.running = false
+ s.mutex.Lock()
+ if s.listener != nil {
+ s.listener.Close()
+ }
+ s.mutex.Unlock()
+}
+
+func (s *Service) handleConnection(conn net.Conn, wg *sync.WaitGroup) {
+ defer func() { s.mutex.Lock(); s.conncounter--; s.mutex.Unlock(); wg.Done() }()
+ reader := bufio.NewReader(conn)
+ writer := bufio.NewWriter(conn)
+
+ for {
+ request, err := reader.ReadBytes('\x00')
+ if err != nil {
+ break
+ }
+
+ err = s.handleMessage(writer, request[:len(request)-1])
+ if err != nil {
+ // FIXME: report error
+ //fmt.Fprintf(os.Stderr, "handleMessage: %v", err)
+ break
+ }
+ }
+
+ conn.Close()
+}
+
+func (s *Service) teardown() {
+ s.mutex.Lock()
+ s.listener = nil
+ s.running = false
+ s.protocol = ""
+ s.address = ""
+ s.mutex.Unlock()
+}
+
+func (s *Service) parseAddress(address string) error {
+ words := strings.SplitN(address, ":", 2)
+ s.protocol = words[0]
+ s.address = words[1]
+
+ // Ignore parameters after ';'
+ words = strings.SplitN(s.address, ";", 2)
+ if words != nil {
+ s.address = words[0]
+ }
+
+ switch s.protocol {
+ case "unix":
+ break
+ case "tcp":
+ break
+
+ default:
+ return fmt.Errorf("Unknown protocol")
+ }
+
+ return nil
+}
+
+func getListener(protocol string, address string) (net.Listener, error) {
+ l := activationListener()
+ if l == nil {
+ if protocol == "unix" && address[0] != '@' {
+ os.Remove(address)
+ }
+
+ var err error
+ l, err = net.Listen(protocol, address)
+ if err != nil {
+ return nil, err
+ }
+
+ if protocol == "unix" && address[0] != '@' {
+ l.(*net.UnixListener).SetUnlinkOnClose(true)
+ }
+ }
+
+ return l, nil
+}
+
+func (s *Service) refreshTimeout(timeout time.Duration) error {
+ switch s.protocol {
+ case "unix":
+ if err := s.listener.(*net.UnixListener).SetDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+
+ case "tcp":
+ if err := s.listener.(*net.TCPListener).SetDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Listen starts a Service.
+func (s *Service) Listen(address string, timeout time.Duration) error {
+ var wg sync.WaitGroup
+ defer func() { s.teardown(); wg.Wait() }()
+
+ s.mutex.Lock()
+ if s.running {
+ s.mutex.Unlock()
+ return fmt.Errorf("Listen(): already running")
+ }
+ s.mutex.Unlock()
+
+ s.parseAddress(address)
+
+ l, err := getListener(s.protocol, s.address)
+ if err != nil {
+ return err
+ }
+
+ s.mutex.Lock()
+ s.listener = l
+ s.running = true
+ s.mutex.Unlock()
+
+ for s.running {
+ if timeout != 0 {
+ if err := s.refreshTimeout(timeout); err != nil {
+ return err
+ }
+ }
+ conn, err := l.Accept()
+ if err != nil {
+ if err.(net.Error).Timeout() {
+ s.mutex.Lock()
+ if s.conncounter == 0 {
+ s.mutex.Unlock()
+ return nil
+ }
+ s.mutex.Unlock()
+ continue
+ }
+ if !s.running {
+ return nil
+ }
+ return err
+ }
+ s.mutex.Lock()
+ s.conncounter++
+ s.mutex.Unlock()
+ wg.Add(1)
+ go s.handleConnection(conn, &wg)
+ }
+
+ return nil
+}
+
+// RegisterInterface registers a varlink.Interface containing struct to the Service
+func (s *Service) RegisterInterface(iface dispatcher) error {
+ name := iface.VarlinkGetName()
+ if _, ok := s.interfaces[name]; ok {
+ return fmt.Errorf("interface '%s' already registered", name)
+ }
+
+ if s.running {
+ return fmt.Errorf("service is already running")
+ }
+ s.interfaces[name] = iface
+ s.descriptions[name] = iface.VarlinkGetDescription()
+ s.names = append(s.names, name)
+
+ return nil
+}
+
+// NewService creates a new Service which implements the list of given varlink interfaces.
+func NewService(vendor string, product string, version string, url string) (*Service, error) {
+ s := Service{
+ vendor: vendor,
+ product: product,
+ version: version,
+ url: url,
+ interfaces: make(map[string]dispatcher),
+ descriptions: make(map[string]string),
+ }
+ err := s.RegisterInterface(orgvarlinkserviceNew())
+
+ return &s, err
+}
diff --git a/vendor/github.com/varlink/go/varlink/varlink_test.go b/vendor/github.com/varlink/go/varlink/varlink_test.go
new file mode 100644
index 000000000..e19e768a2
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/varlink_test.go
@@ -0,0 +1,232 @@
+package varlink
+
+// tests with access to internals
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "strings"
+ "testing"
+)
+
+func expect(t *testing.T, expected string, returned string) {
+ if strings.Compare(returned, expected) != 0 {
+ t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
+ len(expected), expected,
+ len(returned), strings.Replace(returned, "\000", "`+\"\\000\"+`", -1))
+ }
+}
+
+func TestService(t *testing.T) {
+ service, _ := NewService(
+ "Varlink",
+ "Varlink Test",
+ "1",
+ "https://github.com/varlink/go/varlink",
+ )
+
+ t.Run("ZeroMessage", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ if err := service.handleMessage(w, []byte{0}); err == nil {
+ t.Fatal("HandleMessage returned non-error")
+ }
+ })
+
+ t.Run("InvalidJson", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"foo.GetInterfaceDescription" fdgdfg}`)
+ if err := service.handleMessage(w, msg); err == nil {
+ t.Fatal("HandleMessage returned no error on invalid json")
+ }
+ })
+
+ t.Run("WrongInterface", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"foo.GetInterfaceDescription"}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatal("HandleMessage returned error on wrong interface")
+ }
+ expect(t, `{"parameters":{"interface":"foo"},"error":"org.varlink.service.InterfaceNotFound"}`+"\000",
+ b.String())
+ })
+
+ t.Run("InvalidMethod", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"InvalidMethod"}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatal("HandleMessage returned error on invalid method")
+ }
+ expect(t, `{"parameters":{"parameter":"method"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
+ b.String())
+ })
+
+ t.Run("WrongMethod", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.WrongMethod"}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatal("HandleMessage returned error on wrong method")
+ }
+ expect(t, `{"parameters":{"method":"WrongMethod"},"error":"org.varlink.service.MethodNotFound"}`+"\000",
+ b.String())
+ })
+
+ t.Run("GetInterfaceDescriptionNullParameters", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters": null}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"parameter":"parameters"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
+ b.String())
+ })
+
+ t.Run("GetInterfaceDescriptionNoInterface", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{}}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"parameter":"interface"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
+ b.String())
+ })
+
+ t.Run("GetInterfaceDescriptionWrongInterface", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"foo"}}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"parameter":"interface"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
+ b.String())
+ })
+
+ t.Run("GetInterfaceDescription", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"org.varlink.service"}}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"description":"# The Varlink Service Interface is provided by every varlink service. It\n# describes the service and the interfaces it implements.\ninterface org.varlink.service\n\n# Get a list of all the interfaces a service provides and information\n# about the implementation.\nmethod GetInfo() -\u003e (\n vendor: string,\n product: string,\n version: string,\n url: string,\n interfaces: []string\n)\n\n# Get the description of an interface that is implemented by this service.\nmethod GetInterfaceDescription(interface: string) -\u003e (description: string)\n\n# The requested interface was not found.\nerror InterfaceNotFound (interface: string)\n\n# The requested method was not found\nerror MethodNotFound (method: string)\n\n# The interface defines the requested method, but the service does not\n# implement it.\nerror MethodNotImplemented (method: string)\n\n# One of the passed parameters is invalid.\nerror InvalidParameter (parameter: string)"}}`+"\000",
+ b.String())
+ })
+
+ t.Run("GetInfo", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.varlink.service.GetInfo"}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"vendor":"Varlink","product":"Varlink Test","version":"1","url":"https://github.com/varlink/go/varlink","interfaces":["org.varlink.service"]}}`+"\000",
+ b.String())
+ })
+}
+
+type VarlinkInterface struct{}
+
+func (s *VarlinkInterface) VarlinkDispatch(call Call, methodname string) error {
+ switch methodname {
+ case "Ping":
+ if !call.WantsMore() {
+ return fmt.Errorf("More flag not passed")
+ }
+ if call.IsOneShot() {
+ return fmt.Errorf("OneShot flag set")
+ }
+ call.Continues = true
+ if err := call.Reply(nil); err != nil {
+ return err
+ }
+ if err := call.Reply(nil); err != nil {
+ return err
+ }
+ call.Continues = false
+ if err := call.Reply(nil); err != nil {
+ return err
+ }
+ return nil
+
+ case "PingError":
+ return call.ReplyError("org.example.test.PingError", nil)
+ }
+
+ call.Continues = true
+ if err := call.Reply(nil); err == nil {
+ return fmt.Errorf("call.Reply did not fail for Continues/More mismatch")
+ }
+ call.Continues = false
+
+ if err := call.ReplyError("WrongName", nil); err == nil {
+ return fmt.Errorf("call.ReplyError accepted invalid error name")
+ }
+
+ if err := call.ReplyError("org.varlink.service.MethodNotImplemented", nil); err == nil {
+ return fmt.Errorf("call.ReplyError accepted org.varlink.service error")
+ }
+
+ return call.ReplyMethodNotImplemented(methodname)
+}
+func (s *VarlinkInterface) VarlinkGetName() string {
+ return `org.example.test`
+}
+
+func (s *VarlinkInterface) VarlinkGetDescription() string {
+ return "#"
+}
+
+func TestMoreService(t *testing.T) {
+ newTestInterface := new(VarlinkInterface)
+
+ service, _ := NewService(
+ "Varlink",
+ "Varlink Test",
+ "1",
+ "https://github.com/varlink/go/varlink",
+ )
+
+ if err := service.RegisterInterface(newTestInterface); err != nil {
+ t.Fatalf("Couldn't register service: %v", err)
+ }
+
+ t.Run("MethodNotImplemented", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.example.test.Pingf"}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"parameters":{"method":"Pingf"},"error":"org.varlink.service.MethodNotImplemented"}`+"\000",
+ b.String())
+ })
+
+ t.Run("PingError", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.example.test.PingError", "more" : true}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"error":"org.example.test.PingError"}`+"\000",
+ b.String())
+ })
+ t.Run("MoreTest", func(t *testing.T) {
+ var b bytes.Buffer
+ w := bufio.NewWriter(&b)
+ msg := []byte(`{"method":"org.example.test.Ping", "more" : true}`)
+ if err := service.handleMessage(w, msg); err != nil {
+ t.Fatalf("HandleMessage returned error: %v", err)
+ }
+ expect(t, `{"continues":true}`+"\000"+`{"continues":true}`+"\000"+`{}`+"\000",
+ b.String())
+ })
+}