Add support for file editor
This commit is contained in:
@@ -32,27 +32,34 @@ const (
|
|||||||
|
|
||||||
type DockerApi interface {
|
type DockerApi interface {
|
||||||
GetClient() *client.Client
|
GetClient() *client.Client
|
||||||
CreateNetwork(id string, opts types.NetworkCreate) error
|
|
||||||
ConnectNetwork(container, network, ip string) (string, error)
|
NetworkCreate(id string, opts types.NetworkCreate) error
|
||||||
|
NetworkConnect(container, network, ip string) (string, error)
|
||||||
NetworkInspect(id string) (types.NetworkResource, error)
|
NetworkInspect(id string) (types.NetworkResource, error)
|
||||||
GetDaemonInfo() (types.Info, error)
|
NetworkDelete(id string) error
|
||||||
GetDaemonHost() string
|
NetworkDisconnect(containerId, networkId string) error
|
||||||
|
|
||||||
|
DaemonInfo() (types.Info, error)
|
||||||
|
DaemonHost() string
|
||||||
|
|
||||||
GetSwarmPorts() ([]string, []uint16, error)
|
GetSwarmPorts() ([]string, []uint16, error)
|
||||||
GetPorts() ([]uint16, error)
|
GetPorts() ([]uint16, error)
|
||||||
GetContainerStats(name string) (io.ReadCloser, error)
|
|
||||||
|
ContainerStats(name string) (io.ReadCloser, error)
|
||||||
ContainerResize(name string, rows, cols uint) error
|
ContainerResize(name string, rows, cols uint) error
|
||||||
ContainerRename(old, new string) error
|
ContainerRename(old, new string) error
|
||||||
|
ContainerDelete(name string) error
|
||||||
|
ContainerCreate(opts CreateContainerOpts) error
|
||||||
|
ContainerIPs(id string) (map[string]string, error)
|
||||||
|
ExecAttach(instanceName string, command []string, out io.Writer) (int, error)
|
||||||
|
Exec(instanceName string, command []string) (int, error)
|
||||||
|
|
||||||
CreateAttachConnection(name string) (net.Conn, error)
|
CreateAttachConnection(name string) (net.Conn, error)
|
||||||
CopyToContainer(containerName, destination, fileName string, content io.Reader) error
|
CopyToContainer(containerName, destination, fileName string, content io.Reader) error
|
||||||
DeleteContainer(name string) error
|
CopyFromContainer(containerName, filePath string) (io.Reader, error)
|
||||||
CreateContainer(opts CreateContainerOpts) error
|
|
||||||
GetContainerIPs(id string) (map[string]string, error)
|
|
||||||
ExecAttach(instanceName string, command []string, out io.Writer) (int, error)
|
|
||||||
DisconnectNetwork(containerId, networkId string) error
|
|
||||||
DeleteNetwork(id string) error
|
|
||||||
Exec(instanceName string, command []string) (int, error)
|
|
||||||
SwarmInit(advertiseAddr string) (*SwarmTokens, error)
|
SwarmInit(advertiseAddr string) (*SwarmTokens, error)
|
||||||
SwarmJoin(addr, token string) error
|
SwarmJoin(addr, token string) error
|
||||||
|
|
||||||
ConfigCreate(name string, labels map[string]string, data []byte) error
|
ConfigCreate(name string, labels map[string]string, data []byte) error
|
||||||
ConfigDelete(name string) error
|
ConfigDelete(name string) error
|
||||||
}
|
}
|
||||||
@@ -82,7 +89,7 @@ func (d *docker) ConfigDelete(name string) error {
|
|||||||
return d.c.ConfigRemove(context.Background(), name)
|
return d.c.ConfigRemove(context.Background(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) CreateNetwork(id string, opts types.NetworkCreate) error {
|
func (d *docker) NetworkCreate(id string, opts types.NetworkCreate) error {
|
||||||
_, err := d.c.NetworkCreate(context.Background(), id, opts)
|
_, err := d.c.NetworkCreate(context.Background(), id, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -94,7 +101,7 @@ func (d *docker) CreateNetwork(id string, opts types.NetworkCreate) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) ConnectNetwork(containerId, networkId, ip string) (string, error) {
|
func (d *docker) NetworkConnect(containerId, networkId, ip string) (string, error) {
|
||||||
settings := &network.EndpointSettings{}
|
settings := &network.EndpointSettings{}
|
||||||
if ip != "" {
|
if ip != "" {
|
||||||
settings.IPAddress = ip
|
settings.IPAddress = ip
|
||||||
@@ -125,11 +132,11 @@ func (d *docker) NetworkInspect(id string) (types.NetworkResource, error) {
|
|||||||
return d.c.NetworkInspect(context.Background(), id, types.NetworkInspectOptions{})
|
return d.c.NetworkInspect(context.Background(), id, types.NetworkInspectOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) GetDaemonInfo() (types.Info, error) {
|
func (d *docker) DaemonInfo() (types.Info, error) {
|
||||||
return d.c.Info(context.Background())
|
return d.c.Info(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) GetDaemonHost() string {
|
func (d *docker) DaemonHost() string {
|
||||||
return d.c.DaemonHost()
|
return d.c.DaemonHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +187,7 @@ func (d *docker) GetPorts() ([]uint16, error) {
|
|||||||
return openPorts, nil
|
return openPorts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) GetContainerStats(name string) (io.ReadCloser, error) {
|
func (d *docker) ContainerStats(name string) (io.ReadCloser, error) {
|
||||||
stats, err := d.c.ContainerStats(context.Background(), name, false)
|
stats, err := d.c.ContainerStats(context.Background(), name, false)
|
||||||
|
|
||||||
return stats.Body, err
|
return stats.Body, err
|
||||||
@@ -222,7 +229,21 @@ func (d *docker) CopyToContainer(containerName, destination, fileName string, co
|
|||||||
return d.c.CopyToContainer(context.Background(), containerName, destination, r, types.CopyToContainerOptions{AllowOverwriteDirWithFile: true})
|
return d.c.CopyToContainer(context.Background(), containerName, destination, r, types.CopyToContainerOptions{AllowOverwriteDirWithFile: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) DeleteContainer(name string) error {
|
func (d *docker) CopyFromContainer(containerName, filePath string) (io.Reader, error) {
|
||||||
|
rc, stat, err := d.c.CopyFromContainer(context.Background(), containerName, filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if stat.Mode.IsDir() {
|
||||||
|
return nil, fmt.Errorf("Copying directories is not supported")
|
||||||
|
}
|
||||||
|
tr := tar.NewReader(rc)
|
||||||
|
// advance to the only possible file in the tar archive
|
||||||
|
tr.Next()
|
||||||
|
return tr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *docker) ContainerDelete(name string) error {
|
||||||
err := d.c.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{Force: true, RemoveVolumes: true})
|
err := d.c.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{Force: true, RemoveVolumes: true})
|
||||||
d.c.VolumeRemove(context.Background(), name, true)
|
d.c.VolumeRemove(context.Background(), name, true)
|
||||||
return err
|
return err
|
||||||
@@ -242,7 +263,7 @@ type CreateContainerOpts struct {
|
|||||||
Networks []string
|
Networks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) CreateContainer(opts CreateContainerOpts) (err error) {
|
func (d *docker) ContainerCreate(opts CreateContainerOpts) (err error) {
|
||||||
// Make sure directories are available for the new instance container
|
// Make sure directories are available for the new instance container
|
||||||
containerDir := "/var/run/pwd"
|
containerDir := "/var/run/pwd"
|
||||||
containerCertDir := fmt.Sprintf("%s/certs", containerDir)
|
containerCertDir := fmt.Sprintf("%s/certs", containerDir)
|
||||||
@@ -382,7 +403,7 @@ func (d *docker) CreateContainer(opts CreateContainerOpts) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) GetContainerIPs(id string) (map[string]string, error) {
|
func (d *docker) ContainerIPs(id string) (map[string]string, error) {
|
||||||
cinfo, err := d.c.ContainerInspect(context.Background(), id)
|
cinfo, err := d.c.ContainerInspect(context.Background(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -468,7 +489,7 @@ func (d *docker) Exec(instanceName string, command []string) (int, error) {
|
|||||||
return ins.ExitCode, nil
|
return ins.ExitCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) DisconnectNetwork(containerId, networkId string) error {
|
func (d *docker) NetworkDisconnect(containerId, networkId string) error {
|
||||||
err := d.c.NetworkDisconnect(context.Background(), networkId, containerId, true)
|
err := d.c.NetworkDisconnect(context.Background(), networkId, containerId, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -480,7 +501,7 @@ func (d *docker) DisconnectNetwork(containerId, networkId string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docker) DeleteNetwork(id string) error {
|
func (d *docker) NetworkDelete(id string) error {
|
||||||
err := d.c.NetworkRemove(context.Background(), id)
|
err := d.c.NetworkRemove(context.Background(), id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"docker.io/go-docker/api/types"
|
|
||||||
client "docker.io/go-docker"
|
client "docker.io/go-docker"
|
||||||
|
"docker.io/go-docker/api/types"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,12 +19,12 @@ func (m *Mock) GetClient() *client.Client {
|
|||||||
return args.Get(0).(*client.Client)
|
return args.Get(0).(*client.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mock) CreateNetwork(id string, opts types.NetworkCreate) error {
|
func (m *Mock) NetworkCreate(id string, opts types.NetworkCreate) error {
|
||||||
args := m.Called(id, opts)
|
args := m.Called(id, opts)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mock) ConnectNetwork(container, network, ip string) (string, error) {
|
func (m *Mock) NetworkConnect(container, network, ip string) (string, error) {
|
||||||
args := m.Called(container, network, ip)
|
args := m.Called(container, network, ip)
|
||||||
return args.String(0), args.Error(1)
|
return args.String(0), args.Error(1)
|
||||||
}
|
}
|
||||||
@@ -34,12 +34,12 @@ func (m *Mock) NetworkInspect(id string) (types.NetworkResource, error) {
|
|||||||
return args.Get(0).(types.NetworkResource), args.Error(1)
|
return args.Get(0).(types.NetworkResource), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mock) GetDaemonInfo() (types.Info, error) {
|
func (m *Mock) DaemonInfo() (types.Info, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(types.Info), args.Error(1)
|
return args.Get(0).(types.Info), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mock) GetDaemonHost() string {
|
func (m *Mock) DaemonHost() string {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ func (m *Mock) GetPorts() ([]uint16, error) {
|
|||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]uint16), args.Error(1)
|
return args.Get(0).([]uint16), args.Error(1)
|
||||||
}
|
}
|
||||||
func (m *Mock) GetContainerStats(name string) (io.ReadCloser, error) {
|
func (m *Mock) ContainerStats(name string) (io.ReadCloser, error) {
|
||||||
args := m.Called(name)
|
args := m.Called(name)
|
||||||
return args.Get(0).(io.ReadCloser), args.Error(1)
|
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||||
}
|
}
|
||||||
@@ -73,15 +73,20 @@ func (m *Mock) CopyToContainer(containerName, destination, fileName string, cont
|
|||||||
args := m.Called(containerName, destination, fileName, content)
|
args := m.Called(containerName, destination, fileName, content)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
func (m *Mock) DeleteContainer(id string) error {
|
|
||||||
|
func (m *Mock) CopyFromContainer(containerName, filePath string) (io.Reader, error) {
|
||||||
|
args := m.Called(containerName, filePath)
|
||||||
|
return args.Get(0).(io.Reader), args.Error(1)
|
||||||
|
}
|
||||||
|
func (m *Mock) ContainerDelete(id string) error {
|
||||||
args := m.Called(id)
|
args := m.Called(id)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
func (m *Mock) CreateContainer(opts CreateContainerOpts) error {
|
func (m *Mock) ContainerCreate(opts CreateContainerOpts) error {
|
||||||
args := m.Called(opts)
|
args := m.Called(opts)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
func (m *Mock) GetContainerIPs(id string) (map[string]string, error) {
|
func (m *Mock) ContainerIPs(id string) (map[string]string, error) {
|
||||||
args := m.Called(id)
|
args := m.Called(id)
|
||||||
return args.Get(0).(map[string]string), args.Error(1)
|
return args.Get(0).(map[string]string), args.Error(1)
|
||||||
}
|
}
|
||||||
@@ -90,11 +95,11 @@ func (m *Mock) ExecAttach(instanceName string, command []string, out io.Writer)
|
|||||||
args := m.Called(instanceName, command, out)
|
args := m.Called(instanceName, command, out)
|
||||||
return args.Int(0), args.Error(1)
|
return args.Int(0), args.Error(1)
|
||||||
}
|
}
|
||||||
func (m *Mock) DisconnectNetwork(containerId, networkId string) error {
|
func (m *Mock) NetworkDisconnect(containerId, networkId string) error {
|
||||||
args := m.Called(containerId, networkId)
|
args := m.Called(containerId, networkId)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
func (m *Mock) DeleteNetwork(id string) error {
|
func (m *Mock) NetworkDelete(id string) error {
|
||||||
args := m.Called(id)
|
args := m.Called(id)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
FROM franela/kind_builder
|
|
||||||
|
|
||||||
COPY motd /etc/motd
|
|
||||||
RUN echo $'cat /etc/motd \n\
|
|
||||||
export PS1="[\h \W]$ "' >> /root/.bash_profile
|
|
||||||
|
|
||||||
CMD systemctl start docker && systemctl start kubelet \
|
|
||||||
&& while true; do bash -l; done
|
|
||||||
2
dockerfiles/pwm/.gitconfig
Normal file
2
dockerfiles/pwm/.gitconfig
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[url "https://"]
|
||||||
|
insteadOf = git://
|
||||||
73
dockerfiles/pwm/.inputrc
Normal file
73
dockerfiles/pwm/.inputrc
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# /etc/inputrc - global inputrc for libreadline
|
||||||
|
# See readline(3readline) and `info rluserman' for more information.
|
||||||
|
|
||||||
|
# Be 8 bit clean.
|
||||||
|
set input-meta on
|
||||||
|
set output-meta on
|
||||||
|
|
||||||
|
# To allow the use of 8bit-characters like the german umlauts, uncomment
|
||||||
|
# the line below. However this makes the meta key not work as a meta key,
|
||||||
|
# which is annoying to those which don't need to type in 8-bit characters.
|
||||||
|
|
||||||
|
# set convert-meta off
|
||||||
|
|
||||||
|
# try to enable the application keypad when it is called. Some systems
|
||||||
|
# need this to enable the arrow keys.
|
||||||
|
# set enable-keypad on
|
||||||
|
|
||||||
|
# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys
|
||||||
|
|
||||||
|
# do not bell on tab-completion
|
||||||
|
# set bell-style none
|
||||||
|
# set bell-style visible
|
||||||
|
|
||||||
|
# some defaults / modifications for the emacs mode
|
||||||
|
$if mode=emacs
|
||||||
|
|
||||||
|
# allow the use of the Home/End keys
|
||||||
|
"\e[1~": beginning-of-line
|
||||||
|
"\e[4~": end-of-line
|
||||||
|
|
||||||
|
# allow the use of the Delete/Insert keys
|
||||||
|
"\e[3~": delete-char
|
||||||
|
"\e[2~": quoted-insert
|
||||||
|
|
||||||
|
# mappings for "page up" and "page down" to step to the beginning/end
|
||||||
|
# of the history
|
||||||
|
# "\e[5~": beginning-of-history
|
||||||
|
# "\e[6~": end-of-history
|
||||||
|
|
||||||
|
# alternate mappings for "page up" and "page down" to search the history
|
||||||
|
# "\e[5~": history-search-backward
|
||||||
|
# "\e[6~": history-search-forward
|
||||||
|
|
||||||
|
# mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving
|
||||||
|
"\e[1;5C": forward-word
|
||||||
|
"\e[1;5D": backward-word
|
||||||
|
"\e[5C": forward-word
|
||||||
|
"\e[5D": backward-word
|
||||||
|
"\e\e[C": forward-word
|
||||||
|
"\e\e[D": backward-word
|
||||||
|
|
||||||
|
$if term=rxvt
|
||||||
|
"\e[7~": beginning-of-line
|
||||||
|
"\e[8~": end-of-line
|
||||||
|
"\eOc": forward-word
|
||||||
|
"\eOd": backward-word
|
||||||
|
$endif
|
||||||
|
|
||||||
|
# for non RH/Debian xterm, can't hurt for RH/Debian xterm
|
||||||
|
# "\eOH": beginning-of-line
|
||||||
|
# "\eOF": end-of-line
|
||||||
|
|
||||||
|
# for freebsd console
|
||||||
|
# "\e[H": beginning-of-line
|
||||||
|
# "\e[F": end-of-line
|
||||||
|
|
||||||
|
$endif
|
||||||
|
|
||||||
|
# faster completion
|
||||||
|
set show-all-if-ambiguous on
|
||||||
|
|
||||||
|
"\e[A": history-search-backward
|
||||||
|
"\e[B": history-search-forward
|
||||||
5
dockerfiles/pwm/.profile
Normal file
5
dockerfiles/pwm/.profile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export PS1='\e[1m\e[31m[\h] \e[32m\e[34m\u@$(hostname -i)\e[35m \w\e[0m\n$ '
|
||||||
|
alias vi='vim'
|
||||||
|
export PATH=$PATH:/root/go/bin
|
||||||
|
cat /etc/motd
|
||||||
|
echo $BASHPID > /var/run/cwd
|
||||||
6
dockerfiles/pwm/.vimrc
Normal file
6
dockerfiles/pwm/.vimrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
syntax on
|
||||||
|
set autoindent
|
||||||
|
set expandtab
|
||||||
|
set number
|
||||||
|
set shiftwidth=2
|
||||||
|
set softtabstop=2
|
||||||
44
dockerfiles/pwm/Dockerfile
Normal file
44
dockerfiles/pwm/Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
ARG VERSION=docker:stable-dind
|
||||||
|
FROM ${VERSION}
|
||||||
|
|
||||||
|
RUN apk add --no-cache git tmux vim curl bash build-base qemu-img qemu-system-x86_64
|
||||||
|
|
||||||
|
ENV GOPATH /root/go
|
||||||
|
ENV PATH $PATH:$GOPATH
|
||||||
|
|
||||||
|
# Use specific moby commit due to vendoring mismatch
|
||||||
|
ENV MOBY_COMMIT="d9d2a91780b34b92e669bbfa099f613bd9fad6bb"
|
||||||
|
|
||||||
|
RUN mkdir /root/go && apk add --no-cache go \
|
||||||
|
&& go get -u -d github.com/moby/tool/cmd/moby && (cd $GOPATH/src/github.com/moby/tool/cmd/moby && git checkout $MOBY_COMMIT && go install) \
|
||||||
|
&& go get -u github.com/linuxkit/linuxkit/src/cmd/linuxkit \
|
||||||
|
&& rm -rf /root/go/pkg && rm -rf /root/go/src && rm -rf /usr/lib/go
|
||||||
|
|
||||||
|
|
||||||
|
# Add bash completion and set bash as default shell
|
||||||
|
RUN mkdir /etc/bash_completion.d \
|
||||||
|
&& curl https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker -o /etc/bash_completion.d/docker \
|
||||||
|
&& sed -i "s/ash/bash/" /etc/passwd
|
||||||
|
|
||||||
|
|
||||||
|
# Replace modprobe with a no-op to get rid of spurious warnings
|
||||||
|
# (note: we can't just symlink to /bin/true because it might be busybox)
|
||||||
|
RUN rm /sbin/modprobe && echo '#!/bin/true' >/sbin/modprobe && chmod +x /sbin/modprobe
|
||||||
|
|
||||||
|
# Install a nice vimrc file and prompt (by soulshake)
|
||||||
|
COPY ["sudo", "/usr/local/bin/"]
|
||||||
|
COPY [".vimrc", ".profile", ".inputrc", ".gitconfig", "./root/"]
|
||||||
|
COPY ["motd", "/etc/motd"]
|
||||||
|
COPY ["daemon.json", "/etc/docker/"]
|
||||||
|
|
||||||
|
# Move to our home
|
||||||
|
WORKDIR /root
|
||||||
|
|
||||||
|
|
||||||
|
# Remove IPv6 alias for localhost and start docker in the background ...
|
||||||
|
CMD cat /etc/hosts >/etc/hosts.bak && \
|
||||||
|
sed 's/^::1.*//' /etc/hosts.bak > /etc/hosts && \
|
||||||
|
mount -t securityfs none /sys/kernel/security && \
|
||||||
|
dockerd &>/docker.log & \
|
||||||
|
while true ; do /bin/bash -l; done
|
||||||
|
# ... and then put a shell in the foreground, restarting it if it exits
|
||||||
7
dockerfiles/pwm/daemon.json
Normal file
7
dockerfiles/pwm/daemon.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"experimental": true,
|
||||||
|
"debug": true,
|
||||||
|
"log-level": "info",
|
||||||
|
"insecure-registries": ["127.0.0.1"],
|
||||||
|
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
|
||||||
|
}
|
||||||
8
dockerfiles/pwm/motd
Normal file
8
dockerfiles/pwm/motd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
###############################################################
|
||||||
|
# WARNING!!!! #
|
||||||
|
# This is a sandbox environment. Using personal credentials #
|
||||||
|
# is HIGHLY! discouraged. Any consequences of doing so are #
|
||||||
|
# completely the user's responsibilites. #
|
||||||
|
# #
|
||||||
|
# The PWD team. #
|
||||||
|
###############################################################
|
||||||
5
dockerfiles/pwm/sudo
Executable file
5
dockerfiles/pwm/sudo
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This is shim to help with the case were pasted commands from a readme assume you are not root. Since this isto be run by root, it should effectively be a dummy command that allows the parameters to pass through.
|
||||||
|
|
||||||
|
exec $@
|
||||||
@@ -68,8 +68,10 @@ func Register(extend HandlerExtender) {
|
|||||||
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/uploads", FileUpload).Methods("POST")
|
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/uploads", FileUpload).Methods("POST")
|
||||||
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}", DeleteInstance).Methods("DELETE")
|
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}", DeleteInstance).Methods("DELETE")
|
||||||
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/exec", Exec).Methods("POST")
|
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/exec", Exec).Methods("POST")
|
||||||
|
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/fstree", fsTree).Methods("GET")
|
||||||
|
corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/file", file).Methods("GET")
|
||||||
|
|
||||||
r.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/editor.html", func(rw http.ResponseWriter, r *http.Request) {
|
r.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/editor", func(rw http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(rw, r, "www/editor.html")
|
http.ServeFile(rw, r, "www/editor.html")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
53
handlers/file_instance.go
Normal file
53
handlers/file_instance.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func file(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
sessionId := vars["sessionId"]
|
||||||
|
instanceName := vars["instanceName"]
|
||||||
|
|
||||||
|
query := req.URL.Query()
|
||||||
|
|
||||||
|
path := query.Get("path")
|
||||||
|
|
||||||
|
if path == "" {
|
||||||
|
rw.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s, _ := core.SessionGet(sessionId)
|
||||||
|
if s == nil {
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i := core.InstanceGet(s, instanceName)
|
||||||
|
if i == nil {
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceFile, err := core.InstanceFile(i, path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := base64.NewEncoder(base64.StdEncoding, rw)
|
||||||
|
|
||||||
|
if _, err = io.Copy(encoder, instanceFile); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
42
handlers/fstree_instance.go
Normal file
42
handlers/fstree_instance.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fsTree(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
sessionId := vars["sessionId"]
|
||||||
|
instanceName := vars["instanceName"]
|
||||||
|
|
||||||
|
s, _ := core.SessionGet(sessionId)
|
||||||
|
if s == nil {
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i := core.InstanceGet(s, instanceName)
|
||||||
|
if i == nil {
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err := core.InstanceFSTree(i)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.Header().Set("content-type", "application/json")
|
||||||
|
if _, err = io.Copy(rw, tree); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,11 +83,11 @@ func (d *DinD) InstanceNew(session *types.Session, conf types.InstanceConfig) (*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := dockerClient.CreateContainer(opts); err != nil {
|
if err := dockerClient.ContainerCreate(opts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, err := dockerClient.GetContainerIPs(containerName)
|
ips, err := dockerClient.ContainerIPs(containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ func (d *DinD) InstanceDelete(session *types.Session, instance *types.Instance)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = dockerClient.DeleteContainer(instance.Name)
|
err = dockerClient.ContainerDelete(instance.Name)
|
||||||
if err != nil && !strings.Contains(err.Error(), "No such container") {
|
if err != nil && !strings.Contains(err.Error(), "No such container") {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,40 @@ func (d *DinD) InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
|||||||
return dockerClient.Exec(instance.Name, cmd)
|
return dockerClient.Exec(instance.Name, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DinD) InstanceFSTree(instance *types.Instance) (io.Reader, error) {
|
||||||
|
session, err := d.getSession(instance.SessionId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dockerClient, err := d.factory.GetForSession(session)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
if c, err := dockerClient.ExecAttach(instance.Name, []string{"bash", "-c", `tree --noreport -J $HOME`}, b); c > 0 {
|
||||||
|
log.Println(b.String())
|
||||||
|
return nil, fmt.Errorf("Error %d trying list directories", c)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DinD) InstanceFile(instance *types.Instance, filePath string) (io.Reader, error) {
|
||||||
|
session, err := d.getSession(instance.SessionId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dockerClient, err := d.factory.GetForSession(session)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockerClient.CopyFromContainer(instance.Name, filePath)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DinD) InstanceResizeTerminal(instance *types.Instance, rows, cols uint) error {
|
func (d *DinD) InstanceResizeTerminal(instance *types.Instance, rows, cols uint) error {
|
||||||
session, err := d.getSession(instance.SessionId)
|
session, err := d.getSession(instance.SessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (p *overlaySessionProvisioner) SessionNew(ctx context.Context, s *types.Ses
|
|||||||
// We assume we are out of capacity
|
// We assume we are out of capacity
|
||||||
return fmt.Errorf("Out of capacity")
|
return fmt.Errorf("Out of capacity")
|
||||||
}
|
}
|
||||||
u, _ := url.Parse(dockerClient.GetDaemonHost())
|
u, _ := url.Parse(dockerClient.DaemonHost())
|
||||||
if u.Host == "" {
|
if u.Host == "" {
|
||||||
s.Host = "localhost"
|
s.Host = "localhost"
|
||||||
} else {
|
} else {
|
||||||
@@ -36,13 +36,13 @@ func (p *overlaySessionProvisioner) SessionNew(ctx context.Context, s *types.Ses
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := dtypes.NetworkCreate{Driver: "overlay", Attachable: true}
|
opts := dtypes.NetworkCreate{Driver: "overlay", Attachable: true}
|
||||||
if err := dockerClient.CreateNetwork(s.Id, opts); err != nil {
|
if err := dockerClient.NetworkCreate(s.Id, opts); err != nil {
|
||||||
log.Println("ERROR NETWORKING", err)
|
log.Println("ERROR NETWORKING", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Network [%s] created for session [%s]\n", s.Id, s.Id)
|
log.Printf("Network [%s] created for session [%s]\n", s.Id, s.Id)
|
||||||
|
|
||||||
ip, err := dockerClient.ConnectNetwork(config.L2ContainerName, s.Id, s.PwdIpAddress)
|
ip, err := dockerClient.NetworkConnect(config.L2ContainerName, s.Id, s.PwdIpAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
@@ -58,14 +58,14 @@ func (p *overlaySessionProvisioner) SessionClose(s *types.Session) error {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := dockerClient.DisconnectNetwork(config.L2ContainerName, s.Id); err != nil {
|
if err := dockerClient.NetworkDisconnect(config.L2ContainerName, s.Id); err != nil {
|
||||||
if !strings.Contains(err.Error(), "is not connected to the network") {
|
if !strings.Contains(err.Error(), "is not connected to the network") {
|
||||||
log.Println("ERROR NETWORKING", err)
|
log.Println("ERROR NETWORKING", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Disconnected l2 from network [%s]\n", s.Id)
|
log.Printf("Disconnected l2 from network [%s]\n", s.Id)
|
||||||
if err := dockerClient.DeleteNetwork(s.Id); err != nil {
|
if err := dockerClient.NetworkDelete(s.Id); err != nil {
|
||||||
if !strings.Contains(err.Error(), "not found") {
|
if !strings.Contains(err.Error(), "not found") {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type InstanceProvisionerApi interface {
|
|||||||
InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error)
|
InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error)
|
||||||
InstanceDelete(session *types.Session, instance *types.Instance) error
|
InstanceDelete(session *types.Session, instance *types.Instance) error
|
||||||
InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
||||||
|
InstanceFSTree(instance *types.Instance) (io.Reader, error)
|
||||||
|
InstanceFile(instance *types.Instance, filePath string) (io.Reader, error)
|
||||||
|
|
||||||
InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error
|
InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error
|
||||||
InstanceGetTerminal(instance *types.Instance) (net.Conn, error)
|
InstanceGetTerminal(instance *types.Instance) (net.Conn, error)
|
||||||
|
|||||||
@@ -155,6 +155,15 @@ func (d *windows) InstanceExec(instance *types.Instance, cmd []string) (int, err
|
|||||||
return ex.ExitCode, nil
|
return ex.ExitCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *windows) InstanceFSTree(instance *types.Instance) (io.Reader, error) {
|
||||||
|
//TODO implement
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (d *windows) InstanceFile(instance *types.Instance, filePath string) (io.Reader, error) {
|
||||||
|
//TODO implement
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *windows) releaseInstance(instanceId string) error {
|
func (d *windows) releaseInstance(instanceId string) error {
|
||||||
return d.storage.WindowsInstanceDelete(instanceId)
|
return d.storage.WindowsInstanceDelete(instanceId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ func TestClientNew(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("InstanceCount").Return(0, nil)
|
_s.On("InstanceCount").Return(0, nil)
|
||||||
@@ -72,9 +72,9 @@ func TestClientCount(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("ClientPut", mock.AnythingOfType("*types.Client")).Return(nil)
|
_s.On("ClientPut", mock.AnythingOfType("*types.Client")).Return(nil)
|
||||||
_s.On("ClientCount").Return(1, nil)
|
_s.On("ClientCount").Return(1, nil)
|
||||||
@@ -113,9 +113,9 @@ func TestClientResizeViewPort(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("InstanceCount").Return(0, nil)
|
_s.On("InstanceCount").Return(0, nil)
|
||||||
|
|||||||
@@ -149,3 +149,23 @@ func (p *pwd) InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
|||||||
}
|
}
|
||||||
return exitCode, nil
|
return exitCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *pwd) InstanceFSTree(instance *types.Instance) (io.Reader, error) {
|
||||||
|
defer observeAction("InstanceFSTree", time.Now())
|
||||||
|
|
||||||
|
prov, err := p.getProvisioner(instance.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return prov.InstanceFSTree(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pwd) InstanceFile(instance *types.Instance, filePath string) (io.Reader, error) {
|
||||||
|
defer observeAction("InstanceFile", time.Now())
|
||||||
|
|
||||||
|
prov, err := p.getProvisioner(instance.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return prov.InstanceFile(instance, filePath)
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ func TestInstanceNew(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("ClientCount").Return(0, nil)
|
_s.On("ClientCount").Return(0, nil)
|
||||||
@@ -101,8 +101,8 @@ func TestInstanceNew(t *testing.T) {
|
|||||||
HostFQDN: "something.play-with-docker.com",
|
HostFQDN: "something.play-with-docker.com",
|
||||||
Networks: []string{session.Id},
|
Networks: []string{session.Id},
|
||||||
}
|
}
|
||||||
_d.On("CreateContainer", expectedContainerOpts).Return(nil)
|
_d.On("ContainerCreate", expectedContainerOpts).Return(nil)
|
||||||
_d.On("GetContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
_d.On("ContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
||||||
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "node1", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "node1", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("ClientCount").Return(0, nil)
|
_s.On("ClientCount").Return(0, nil)
|
||||||
@@ -171,8 +171,8 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) {
|
|||||||
Privileged: true,
|
Privileged: true,
|
||||||
Networks: []string{session.Id},
|
Networks: []string{session.Id},
|
||||||
}
|
}
|
||||||
_d.On("CreateContainer", expectedContainerOpts).Return(nil)
|
_d.On("ContainerCreate", expectedContainerOpts).Return(nil)
|
||||||
_d.On("GetContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
_d.On("ContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
||||||
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "node1", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "node1", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
@@ -200,9 +200,9 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("ClientCount").Return(0, nil)
|
_s.On("ClientCount").Return(0, nil)
|
||||||
@@ -242,8 +242,8 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) {
|
|||||||
Networks: []string{session.Id},
|
Networks: []string{session.Id},
|
||||||
}
|
}
|
||||||
|
|
||||||
_d.On("CreateContainer", expectedContainerOpts).Return(nil)
|
_d.On("ContainerCreate", expectedContainerOpts).Return(nil)
|
||||||
_d.On("GetContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
_d.On("ContainerIPs", expectedInstance.Name).Return(map[string]string{session.Id: "10.0.0.1"}, nil)
|
||||||
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "redis-master", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_aaaabbbbcccc", "10.0.0.1", "redis-master", "ip10-0-0-1-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
|
|||||||
10
pwd/mock.go
10
pwd/mock.go
@@ -87,6 +87,16 @@ func (m *Mock) InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
|||||||
return args.Int(0), args.Error(1)
|
return args.Int(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Mock) InstanceFSTree(instance *types.Instance) (io.Reader, error) {
|
||||||
|
args := m.Called(instance)
|
||||||
|
return args.Get(0).(io.Reader), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mock) InstanceFile(instance *types.Instance, filePath string) (io.Reader, error) {
|
||||||
|
args := m.Called(instance, filePath)
|
||||||
|
return args.Get(0).(io.Reader), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Mock) ClientNew(id string, session *types.Session) *types.Client {
|
func (m *Mock) ClientNew(id string, session *types.Session) *types.Client {
|
||||||
args := m.Called(id, session)
|
args := m.Called(id, session)
|
||||||
return args.Get(0).(*types.Client)
|
return args.Get(0).(*types.Client)
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ type PWDApi interface {
|
|||||||
InstanceFindBySession(session *types.Session) ([]*types.Instance, error)
|
InstanceFindBySession(session *types.Session) ([]*types.Instance, error)
|
||||||
InstanceDelete(session *types.Session, instance *types.Instance) error
|
InstanceDelete(session *types.Session, instance *types.Instance) error
|
||||||
InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
InstanceExec(instance *types.Instance, cmd []string) (int, error)
|
||||||
|
InstanceFSTree(instance *types.Instance) (io.Reader, error)
|
||||||
|
InstanceFile(instance *types.Instance, filePath string) (io.Reader, error)
|
||||||
|
|
||||||
ClientNew(id string, session *types.Session) *types.Client
|
ClientNew(id string, session *types.Session) *types.Client
|
||||||
ClientResizeViewPort(client *types.Client, cols, rows uint)
|
ClientResizeViewPort(client *types.Client, cols, rows uint)
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ func TestSessionNew(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
_f.On("GetForSession", mock.AnythingOfType("*types.Session")).Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
_s.On("InstanceCount").Return(0, nil)
|
_s.On("InstanceCount").Return(0, nil)
|
||||||
@@ -93,9 +93,9 @@ func TestSessionSetup(t *testing.T) {
|
|||||||
|
|
||||||
_g.On("NewId").Return("aaaabbbbcccc")
|
_g.On("NewId").Return("aaaabbbbcccc")
|
||||||
_f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil)
|
_f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil)
|
||||||
_d.On("CreateNetwork", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
_d.On("NetworkCreate", "aaaabbbbcccc", dtypes.NetworkCreate{Attachable: true, Driver: "overlay"}).Return(nil)
|
||||||
_d.On("GetDaemonHost").Return("localhost")
|
_d.On("DaemonHost").Return("localhost")
|
||||||
_d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
_d.On("NetworkConnect", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil)
|
||||||
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
_s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil)
|
||||||
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
_s.On("InstancePut", mock.AnythingOfType("*types.Instance")).Return(nil)
|
||||||
_s.On("SessionCount").Return(1, nil)
|
_s.On("SessionCount").Return(1, nil)
|
||||||
@@ -104,31 +104,31 @@ func TestSessionSetup(t *testing.T) {
|
|||||||
_s.On("InstanceFindBySessionId", "aaaabbbbcccc").Return([]*types.Instance{}, nil)
|
_s.On("InstanceFindBySessionId", "aaaabbbbcccc").Return([]*types.Instance{}, nil)
|
||||||
|
|
||||||
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager1", Hostname: "manager1", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager1", Hostname: "manager1", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
||||||
_d.On("GetContainerIPs", "aaaabbbb_manager1").Return(map[string]string{"aaaabbbbcccc": "10.0.0.2"}, nil)
|
_d.On("ContainerIPs", "aaaabbbb_manager1").Return(map[string]string{"aaaabbbbcccc": "10.0.0.2"}, nil)
|
||||||
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
||||||
_d.On("SwarmInit").Return(&docker.SwarmTokens{Manager: "managerToken", Worker: "workerToken"}, nil)
|
_d.On("SwarmInit").Return(&docker.SwarmTokens{Manager: "managerToken", Worker: "workerToken"}, nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager1", "10.0.0.2", "manager1", "ip10-0-0-2-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager1", "10.0.0.2", "manager1", "ip10-0-0-2-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager2", Hostname: "manager2", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager2", Hostname: "manager2", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
||||||
_d.On("GetContainerIPs", "aaaabbbb_manager2").Return(map[string]string{"aaaabbbbcccc": "10.0.0.3"}, nil)
|
_d.On("ContainerIPs", "aaaabbbb_manager2").Return(map[string]string{"aaaabbbbcccc": "10.0.0.3"}, nil)
|
||||||
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
||||||
_d.On("SwarmJoin", "10.0.0.2:2377", "managerToken").Return(nil)
|
_d.On("SwarmJoin", "10.0.0.2:2377", "managerToken").Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager2", "10.0.0.3", "manager2", "ip10-0-0-3-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager2", "10.0.0.3", "manager2", "ip10-0-0-3-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind:overlay2-dev", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager3", Hostname: "manager3", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind:overlay2-dev", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_manager3", Hostname: "manager3", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
||||||
_d.On("GetContainerIPs", "aaaabbbb_manager3").Return(map[string]string{"aaaabbbbcccc": "10.0.0.4"}, nil)
|
_d.On("ContainerIPs", "aaaabbbb_manager3").Return(map[string]string{"aaaabbbbcccc": "10.0.0.4"}, nil)
|
||||||
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
||||||
_d.On("SwarmJoin", "10.0.0.2:2377", "managerToken").Return(nil)
|
_d.On("SwarmJoin", "10.0.0.2:2377", "managerToken").Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager3", "10.0.0.4", "manager3", "ip10-0-0-4-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager3", "10.0.0.4", "manager3", "ip10-0-0-4-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_worker1", Hostname: "worker1", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_worker1", Hostname: "worker1", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
||||||
_d.On("GetContainerIPs", "aaaabbbb_worker1").Return(map[string]string{"aaaabbbbcccc": "10.0.0.5"}, nil)
|
_d.On("ContainerIPs", "aaaabbbb_worker1").Return(map[string]string{"aaaabbbbcccc": "10.0.0.5"}, nil)
|
||||||
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
_f.On("GetForInstance", mock.AnythingOfType("*types.Instance")).Return(_d, nil)
|
||||||
_d.On("SwarmJoin", "10.0.0.2:2377", "workerToken").Return(nil)
|
_d.On("SwarmJoin", "10.0.0.2:2377", "workerToken").Return(nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_worker1", "10.0.0.5", "worker1", "ip10-0-0-5-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_worker1", "10.0.0.5", "worker1", "ip10-0-0-5-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_other", Hostname: "other", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
_d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", ContainerName: "aaaabbbb_other", Hostname: "other", Privileged: true, HostFQDN: "localhost", Networks: []string{"aaaabbbbcccc"}}).Return(nil)
|
||||||
_d.On("GetContainerIPs", "aaaabbbb_other").Return(map[string]string{"aaaabbbbcccc": "10.0.0.6"}, nil)
|
_d.On("ContainerIPs", "aaaabbbb_other").Return(map[string]string{"aaaabbbbcccc": "10.0.0.6"}, nil)
|
||||||
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_other", "10.0.0.6", "other", "ip10-0-0-6-aaaabbbbcccc"}).Return()
|
_e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_other", "10.0.0.6", "other", "ip10-0-0-6-aaaabbbbcccc"}).Return()
|
||||||
|
|
||||||
var nilArgs []interface{}
|
var nilArgs []interface{}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func TestCheckSwarmPorts_RunWhenManager(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.On("GetForInstance", i).Return(d, nil)
|
f.On("GetForInstance", i).Return(d, nil)
|
||||||
d.On("GetDaemonInfo").Return(info, nil)
|
d.On("DaemonInfo").Return(info, nil)
|
||||||
d.On("GetSwarmPorts").Return([]string{"aaaabbbb_node1", "aaaabbbb_node2"}, []uint16{8080, 9090}, nil)
|
d.On("GetSwarmPorts").Return([]string{"aaaabbbb_node1", "aaaabbbb_node2"}, []uint16{8080, 9090}, nil)
|
||||||
e.M.On("Emit", CheckSwarmPortsEvent, "aaaabbbbcccc", []interface{}{ClusterPorts{Manager: i.Name, Instances: []string{i.Name, "aaaabbbb_node2"}, Ports: []int{8080, 9090}}}).Return()
|
e.M.On("Emit", CheckSwarmPortsEvent, "aaaabbbbcccc", []interface{}{ClusterPorts{Manager: i.Name, Instances: []string{i.Name, "aaaabbbb_node2"}, Ports: []int{8080, 9090}}}).Return()
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func NewCheckSwarmStatus(e event.EventApi, f docker.FactoryApi) *checkSwarmStatu
|
|||||||
|
|
||||||
func getDockerSwarmStatus(ctx context.Context, client docker.DockerApi) (ClusterStatus, error) {
|
func getDockerSwarmStatus(ctx context.Context, client docker.DockerApi) (ClusterStatus, error) {
|
||||||
status := ClusterStatus{}
|
status := ClusterStatus{}
|
||||||
info, err := client.GetDaemonInfo()
|
info, err := client.DaemonInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status, err
|
return status, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func TestCheckSwarmStatus_RunWhenInactive(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.On("GetForInstance", i).Return(d, nil)
|
f.On("GetForInstance", i).Return(d, nil)
|
||||||
d.On("GetDaemonInfo").Return(infoInactive, nil)
|
d.On("DaemonInfo").Return(infoInactive, nil)
|
||||||
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: false, Instance: "node1"}}).Return()
|
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: false, Instance: "node1"}}).Return()
|
||||||
|
|
||||||
task := NewCheckSwarmStatus(e, f)
|
task := NewCheckSwarmStatus(e, f)
|
||||||
@@ -71,7 +71,7 @@ func TestCheckSwarmStatus_RunWhenLocked(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.On("GetForInstance", i).Return(d, nil)
|
f.On("GetForInstance", i).Return(d, nil)
|
||||||
d.On("GetDaemonInfo").Return(infoLocked, nil)
|
d.On("DaemonInfo").Return(infoLocked, nil)
|
||||||
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: false, Instance: "node1"}}).Return()
|
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: false, Instance: "node1"}}).Return()
|
||||||
|
|
||||||
task := NewCheckSwarmStatus(e, f)
|
task := NewCheckSwarmStatus(e, f)
|
||||||
@@ -103,7 +103,7 @@ func TestCheckSwarmStatus_RunWhenManager(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.On("GetForInstance", i).Return(d, nil)
|
f.On("GetForInstance", i).Return(d, nil)
|
||||||
d.On("GetDaemonInfo").Return(infoLocked, nil)
|
d.On("DaemonInfo").Return(infoLocked, nil)
|
||||||
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: true, IsWorker: false, Instance: "node1"}}).Return()
|
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: true, IsWorker: false, Instance: "node1"}}).Return()
|
||||||
|
|
||||||
task := NewCheckSwarmStatus(e, f)
|
task := NewCheckSwarmStatus(e, f)
|
||||||
@@ -135,7 +135,7 @@ func TestCheckSwarmStatus_RunWhenWorker(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.On("GetForInstance", i).Return(d, nil)
|
f.On("GetForInstance", i).Return(d, nil)
|
||||||
d.On("GetDaemonInfo").Return(infoLocked, nil)
|
d.On("DaemonInfo").Return(infoLocked, nil)
|
||||||
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: true, Instance: "node1"}}).Return()
|
e.M.On("Emit", CheckSwarmStatusEvent, "aaabbbccc", []interface{}{ClusterStatus{IsManager: false, IsWorker: true, Instance: "node1"}}).Return()
|
||||||
|
|
||||||
task := NewCheckSwarmStatus(e, f)
|
task := NewCheckSwarmStatus(e, f)
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (t *collectStats) Run(ctx context.Context, instance *types.Instance) error
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
reader, err := dockerClient.GetContainerStats(instance.Name)
|
reader, err := dockerClient.ContainerStats(instance.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error while trying to collect instance stats", err)
|
log.Println("Error while trying to collect instance stats", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func TestCollectStats_Run(t *testing.T) {
|
|||||||
|
|
||||||
s.On("SessionGet", i.SessionId).Return(sess, nil)
|
s.On("SessionGet", i.SessionId).Return(sess, nil)
|
||||||
f.On("GetForSession", sess).Return(d, nil)
|
f.On("GetForSession", sess).Return(d, nil)
|
||||||
d.On("GetContainerStats", i.Name).Return(nopCloser{bytes.NewReader(b)}, nil)
|
d.On("ContainerStats", i.Name).Return(nopCloser{bytes.NewReader(b)}, nil)
|
||||||
e.M.On("Emit", CollectStatsEvent, "aaaabbbbcccc", []interface{}{InstanceStats{Instance: i.Name, Mem: "0.00% (0B / 0B)", Cpu: "0.00%"}}).Return()
|
e.M.On("Emit", CollectStatsEvent, "aaaabbbbcccc", []interface{}{InstanceStats{Instance: i.Name, Mem: "0.00% (0B / 0B)", Cpu: "0.00%"}}).Return()
|
||||||
|
|
||||||
task := NewCollectStats(e, f, s)
|
task := NewCollectStats(e, f, s)
|
||||||
|
|||||||
15
www/assets/editor.css
Normal file
15
www/assets/editor.css
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.alert-top {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width:100px;
|
||||||
|
display:none;
|
||||||
|
text-align: center;
|
||||||
|
padding: 3px;
|
||||||
|
height: 30px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-md-3 {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
171
www/editor.html
Normal file
171
www/editor.html
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
<title>Editor</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/zTree.v3/3.5.29/css/metroStyle/metroStyle.min.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/assets/editor.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid ">
|
||||||
|
<div id="alert-info" class="alert alert-info alert-top" role="alert">
|
||||||
|
<span class="alert-msg"></span>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="height: 100%">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div>
|
||||||
|
<button type="button" id='treeReloadBtn' class="btn btn-sm">
|
||||||
|
<span class="oi oi-reload" title="Refresh" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="fileTree" class="ztree"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<!-- Nav tabs -->
|
||||||
|
<ul class="nav nav-tabs" id="tabs" role="tablist">
|
||||||
|
</ul>
|
||||||
|
<!-- Tab panes -->
|
||||||
|
<div class="tab-content">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.rawgit.com/zTree/zTree_v3/4f2717d4/js/jquery.ztree.core.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js"></script>
|
||||||
|
<script src="https://cdn.rawgit.com/beatgammit/base64-js/be644dec/base64js.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
var alertShow = function(msg) {
|
||||||
|
$div = $('.alert-info');
|
||||||
|
$div.find('.alert-msg').text(msg);
|
||||||
|
if ($div.css('display') === 'none') {
|
||||||
|
// fadein, fadeout.
|
||||||
|
$div.fadeIn(1000).delay(1000).fadeOut(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//regiters events for newly created tab elements
|
||||||
|
var registerEvents = function(tabId) {
|
||||||
|
//this method will register event on close icon on the tab..
|
||||||
|
$(".closeTab").click(function () {
|
||||||
|
//there are multiple elements which has .closeTab icon so close the tab whose close icon is clicked
|
||||||
|
var tabContentId = $(this).parent().attr("href");
|
||||||
|
$(this).parent().parent().remove(); //remove li of tab
|
||||||
|
$('#tabs a:last').tab('show'); // Select first tab
|
||||||
|
$(tabContentId).remove(); //remove respective tab content
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#fileReload_'+tabId+'Btn').click(function() {
|
||||||
|
var path = $(this).attr('data-file-path');
|
||||||
|
loadFile(path, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#fileSave_'+tabId+'Btn').click(function() {
|
||||||
|
var path = $(this).attr('data-file-path');
|
||||||
|
saveFile(path, tabId);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var getFilePath = function(treeNode) {
|
||||||
|
var parent = treeNode.getParentNode();
|
||||||
|
var path = '';
|
||||||
|
if (parent) {
|
||||||
|
return getFilePath(parent) + '/' + treeNode.name;
|
||||||
|
} else {
|
||||||
|
return treeNode.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var treeClick = function(event, treeId, treeNode, clickFlag) {
|
||||||
|
if (!treeNode.isParent) {
|
||||||
|
var tabId = treeNode.tId;
|
||||||
|
if ($('#tab_' + tabId + '').length == 0) {
|
||||||
|
var filePath = getFilePath(treeNode);
|
||||||
|
$('.nav-tabs').append('<li class="nav-item"><a class="nav-link" data-toggle="tab" role="tab" href="#tab_' + tabId + '"><button class="close closeTab" type="button" >×</button>'+treeNode.name+'</a></li>');
|
||||||
|
$('.tab-content').append(' \
|
||||||
|
<div class="tab-pane" id="tab_' + tabId + '"> \
|
||||||
|
<div style="height: 40px; width: 100%; padding-top: 5px; background-color: #F0F0F0"> \
|
||||||
|
<button type="button" id="fileSave_'+tabId+'Btn" data-file-path="'+filePath+'" class="btn btn-info btn-sm"> \
|
||||||
|
<span class="oi oi-data-transfer-upload" title="Save" aria-hidden="true"></span> Save \
|
||||||
|
</button> \
|
||||||
|
<button type="button" id="fileReload_'+tabId+'Btn" data-file-path="'+filePath+'" class="btn btn-info btn-sm"> \
|
||||||
|
<span class="oi oi-reload" title="Save" aria-hidden="true"></span> Reload \
|
||||||
|
</button> \
|
||||||
|
</div> \
|
||||||
|
<div id="editor_'+ tabId +'" style="height: calc(100vh - 82px); width: 100%;"></div> \
|
||||||
|
</div> \
|
||||||
|
');
|
||||||
|
loadFile(filePath, tabId);
|
||||||
|
registerEvents(tabId);
|
||||||
|
}
|
||||||
|
$('#tabs a[href="#tab_'+ tabId +'"]').tab('show');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var loadFile = function(filePath, tabId) {
|
||||||
|
var editor = ace.edit('editor_'+tabId);
|
||||||
|
$.get('./file?path='+filePath)
|
||||||
|
.done(function( fileBase64 ) {
|
||||||
|
var bytes = base64js.toByteArray(fileBase64);
|
||||||
|
editor.setValue((new TextDecoder("utf-8")).decode(bytes), -1);
|
||||||
|
editor.focus();
|
||||||
|
alertShow('file loaded')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var saveFile = function(filePath, tabId) {
|
||||||
|
var editor = ace.edit('editor_'+tabId);
|
||||||
|
var fileData = new Blob([editor.getValue()], { type: 'text/plain' });
|
||||||
|
var data = new FormData();
|
||||||
|
var fileName = filePath.substr(filePath.lastIndexOf('/'))
|
||||||
|
data.append(fileName,fileData, fileName);
|
||||||
|
$.ajax({
|
||||||
|
url: 'uploads?path='+filePath.substr(0, filePath.lastIndexOf('/')),
|
||||||
|
data: data,
|
||||||
|
cache: false,
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
method: 'POST',
|
||||||
|
type: 'POST', // For jQuery < 1.9
|
||||||
|
success: function(data) {
|
||||||
|
alertShow('file saved')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var setting = {
|
||||||
|
data: {
|
||||||
|
key: {
|
||||||
|
children: "contents"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: {
|
||||||
|
onClick: treeClick
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var populateTree = function() {
|
||||||
|
$.getJSON('./fstree')
|
||||||
|
.done(function( treeData ) {
|
||||||
|
treeData[0].open = true;
|
||||||
|
$.fn.zTree.init($("#fileTree"), setting, treeData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach handlers to tree reload btn
|
||||||
|
$('#treeReloadBtn').click(populateTree);
|
||||||
|
|
||||||
|
// populate tree whenever the page starts
|
||||||
|
populateTree();
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user