How to connect to a remote socket in docker/engine-api? - go

I want to retrieve all docker images of a remote machine, so I am using docker/engine-api: https://github.com/docker/engine-api
I was successful in returning the docker images of my local machine
with the following code:
package main
import (
"fmt"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
"golang.org/x/net/context"
)
func main() {
defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.22", nil, defaultHeaders)
if err != nil {
panic(err)
}
options := types.ContainerListOptions{All: true}
containers, err := cli.ContainerList(context.Background(), options)
if err != nil {
panic(err)
}
for _, c := range containers {
fmt.Println(c.ID)
}
}
But now does anybody know how can I retrieve the docker images of a remote machine given its address,username, and password

That kind of Unix socket is only accessible through proccesses in the same machine.
To access your docker from a remote machine you need to run it with a special configuration to run over ip.
This configuration is DOCKER_OPTS="-H <ip_address>:<port>" (or -H 0.0.0.0:<port> if you whant it to listen on all interfaces), and it depends the version you are running of docker where you must configure it.
Here you can find more information on where to configure DOCKER_OPTS depending on the operation system version.
Hope it helps!

Related

etcd fatal error: failed to reserve page summary memory

when i try to run etcd from user account (Total RAM: 8GB, virtual memory of 1GB) in a 64 bit Linux environment (limited resources), I am getting the following error:
fatal error: failed to reserve page summary memory
runtime stack:
runtime.throw(
{0x108df50?, 0x7fffd8aa6850?}
)
/usr/local/go/src/runtime/panic.go:1047 +0x5d fp=0x7fffd8aa6800 sp=0x7fffd8aa67d0 pc=0x437edd
runtime.(*pageAlloc).sysInit(0x194f2f0)
/usr/local/go/src/runtime/mpagealloc_64bit.go:82 +0x195 fp=0x7fffd8aa6888 sp=0x7fffd8aa6800 pc=0x42c9b5
runtime.(*pageAlloc).init(0x194f2f0, 0x194f2e0, 0x0?)
/usr/local/go/src/runtime/mpagealloc.go:324 +0x70 fp=0x7fffd8aa68b0 sp=0x7fffd8aa6888 pc=0x42a610
runtime.(*mheap).init(0x194f2e0)
/usr/local/go/src/runtime/mheap.go:721 +0x13f fp=0x7fffd8aa68e8 sp=0x7fffd8aa68b0 pc=0x427a3f
runtime.mallocinit()
/usr/local/go/src/runtime/malloc.go:407 +0xb2 fp=0x7fffd8aa6910 sp=0x7fffd8aa68e8 pc=0x40c4f2
runtime.schedinit()
/usr/local/go/src/runtime/proc.go:693 +0xab fp=0x7fffd8aa6970 sp=0x7fffd8aa6910 pc=0x43b8ab
runtime.rt0_go()
/usr/local/go/src/runtime/asm_amd64.s:345 +0x11c fp=0x7fffd8aa6978 sp=0x7fffd8aa6970 pc=0x469c3c
But the same works fine from root account.
Can someone please support?
I was expecting this should give same output from root and user account. This seems like a virtual memory issue to me.
As your request isn't very clear, I'm going to share with you a working piece of code that can successfully interact with etcd:
package main
import (
"context"
"fmt"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
)
func main() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379"},
DialTimeout: 5 * time.Second,
})
if err != nil {
panic(err)
}
defer cli.Close()
// insert values
res, err := cli.Put(context.Background(), "key1", "val1")
if err != nil {
panic(err)
}
fmt.Printf("revision: %q\n", res.Header.Revision)
// delete all keys
defer cli.Delete(context.Background(), "key", clientv3.WithPrefix())
// get object from etcd
key, err := cli.Get(context.Background(), "key1")
if err != nil {
panic(err)
}
fmt.Printf("key: %q\tvalue: %q\n", key.Kvs[0].Key, key.Kvs[0].Value)
}
This code assumes that you've got a running instance of ETCD that listens on port 2379 for incoming requests. I run ETCD with Docker with the following script:
docker run -d -p 2379:2379 -p 2380:2380 --env ALLOW_NONE_AUTHENTICATION=yes --env ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 bitnami/etcd:latest
Hope this helps in clarifying a little bit!

One page REST api on go server to return system MAC address

I have a PHP based web application. On the login page, it makes an AJAX call to a Go server (located on the client machine) to get its MAC address. Below is the Go server code:
package main
import (
"net"
"net/http"
"encoding/json"
)
//define struct for mac address json
type MacAddress struct {
Id string
}
/**
* Get device mac address
*/
func GetMacAddress(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
mac := &MacAddress{Id: ""}
ifas, err := net.Interfaces()
if err != nil {
json.NewEncoder(w).Encode(mac)
return
}
for _, ifa := range ifas {
a := ifa.HardwareAddr.String()
if a != "" {
mac := &MacAddress{Id: a}
json.NewEncoder(w).Encode(mac)
break
}
}
return
}
/**
* Main function
*/
func main() {
http.HandleFunc("/", GetMacAddress)
if err := http.ListenAndServe(":8000", nil); err != nil {
panic(err)
}
}
Result:
{Id: "8c:16:45:5h:1e:0e"}
Here I have 2 questions.
Sometimes i get the error
panic: listen tcp :8000: bind: address already in use
and I manually kill the process. So, what can be improved in my code to avoid this error and close the previously running server?
Can a stand-alone, compiled Go file (created on ubuntu) be run on other systems like windows or linux or mac without having all Go libs and setup?
Information on how to cross-compile a Go program for different operation systems can be found here. Briefly, instead of running go build main.go, run:
env GOARCH=amd64 GOOS=<target_OS> CGO_ENABLED=1 go build -v main.go
I usually have a Makefile to simplify the process of cross-compiling for linux, windows, and macOS.
With regard to your second question, I can only reproduce your error on my machine when I try to ListenAndServe twice. I.e. I suspect that during your debugging cycles, you forgot to close a running server while trying to start a new instance in another terminal window. Make sure to abort your Go program with ctrl + c before running it again.

Using golang connect to docker container with functional tty

Start simple Docker container in Detached(Background) mode
docker run -d --name test ubuntu tail -f /dev/null
Here comes my simple golang code where I connect to running container.
In current connection I want to get functional tty.
package main
import (
"fmt"
"os/exec"
"bufio"
"io"
"os"
"github.com/kr/pty"
)
func main() {
cmd := exec.Command("docker", "exec", "-it", "test", "bin/bash")
tty, err := pty.Start(cmd)
if err != nil {
fmt.Println("Error start cmd", err)
}
defer tty.Close()
go func() {
scanner := bufio.NewScanner(tty)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
go func() {
io.Copy(tty, os.Stdin)
}()
err = cmd.Wait()
if err != nil {
fmt.Println("Error Waiting", err)
}
}
More less it works, but there is couple thinks which is not working as I would run docker command from my terminal.
After login I don't see prompt, like root#ba351b44ca80:/# only after hitting return it appears, but my currsor is in new line where are no prompt;
Also arrow up to get previous command is not working
Only prints out
root#ba351b44ca80:/#
^[[A^[[A^[[A
but behind scene previous command is selected and by hitting return it is executed.
After executing command for cursor is not displayed prompt, like
root#ba351b44ca80:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
<Here my cursor>
go-dockerclient is worth checking out. It is a simple nice abstraction of the Docker remote API. It is used by many opensource projects and is regularly maintained as well.

Simple SSH port forward in Golang

I'm trying to create (and later close) a simple TCP port forward over SSH with Go. I'm new to Golang and statically typed languages. (Coming from Ruby.)
In a terminal I would simply run ssh -L 9000:localhost:9999 user#server.com and this accomplishes what I need. I want to do the same, programmatically with Go.
I have tried using this example as a starting point and this recent test to try to understand what to do, but now I have a pile of confusing jumbled code when it seems like this is actually a very simple thing to do.
Any help would be very much appreciated! :-)
I finally figured out how to do this, I got hints from schmichael in an IRC channel. Thanks to all!
EDIT: A little explanation:
A big part of the problem I was having was that I did not realize a local net.Listener (not just a local net.Conn) needed setup to receive a local request and create the net.Conn before forwarding the bytes.
Also, there exist both port forwards and reverse port forwards and I hadn't previously thought in detail about the fact that a regular port forward also sends bytes back, so copying the remote reader to local writer was not something I had implemented, yet it's very much needed.
Here is an attempt to relate the essence of what this code does:
Listen on local port 9000.
Upon attempted read from local port 9000: (listener.Accept()),
Accept connection and return a local io.Reader and io.Writer and,
Connect to remote server and,
Connect to remote port 9999 returning a io.Reader and io.Writer.
Continually copy local io.Reader bytes to remote io.Writer,
Continually copy remote io.Reader bytes to local io.Writer.
Here is the code:
package main
// Forward from local port 9000 to remote port 9999
import (
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
var (
username = "root"
password = "password"
serverAddrString = "192.168.1.100:22"
localAddrString = "localhost:9000"
remoteAddrString = "localhost:9999"
)
func forward(localConn net.Conn, config *ssh.ClientConfig) {
// Setup sshClientConn (type *ssh.ClientConn)
sshClientConn, err := ssh.Dial("tcp", serverAddrString, config)
if err != nil {
log.Fatalf("ssh.Dial failed: %s", err)
}
// Setup sshConn (type net.Conn)
sshConn, err := sshClientConn.Dial("tcp", remoteAddrString)
// Copy localConn.Reader to sshConn.Writer
go func() {
_, err = io.Copy(sshConn, localConn)
if err != nil {
log.Fatalf("io.Copy failed: %v", err)
}
}()
// Copy sshConn.Reader to localConn.Writer
go func() {
_, err = io.Copy(localConn, sshConn)
if err != nil {
log.Fatalf("io.Copy failed: %v", err)
}
}()
}
func main() {
// Setup SSH config (type *ssh.ClientConfig)
config := &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
}
// Setup localListener (type net.Listener)
localListener, err := net.Listen("tcp", localAddrString)
if err != nil {
log.Fatalf("net.Listen failed: %v", err)
}
for {
// Setup localConn (type net.Conn)
localConn, err := localListener.Accept()
if err != nil {
log.Fatalf("listen.Accept failed: %v", err)
}
go forward(localConn, config)
}
}
I have used your (damick) example code to build a tiny open source tool: SSHTunnel
https://github.com/SommerEngineering/SSHTunnel
Therefore, the code is freely available at GitHub for anyone: Please feel free to use it for learning purposes or for anything else :) I have mentioned your nickname and also linked to this question.
Best regards,
Thorsten.
I'v finished a simple SSH port forward tool called mallory.
It provides HTTP proxy instead of SOCKS proxy, which is really similar to ssh -D.
The core code is similar to damick's answer.
Create ClientConfig
ssh.Dial to remote SSH server with the config and return Client
Now you can use Client.Dial to forward anything you like.
Dial initiates a connection to the addr from the remote host. The resulting connection has a zero LocalAddr() and RemoteAddr().
If you want to serve a SOCKS proxy server, use Client.Dial to connect to the remote server.
I Wrote a tool,Called gosshtool,with this tool,you can easy to create a simple TCP port forward over SSH with Go.https://github.com/scottkiss/gosshtool
I use this tool implemented a port forward server example project:
https://github.com/scottkiss/gooverssh

Specify local IP address in net.DialTCP

package main
import (
"fmt"
"net"
)
func main() {
var localaddr net.TCPAddr
var remoteaddr net.TCPAddr
localaddr.IP = net.ParseIP("192.168.1.104")
localaddr.Port = 6000
remoteaddr.IP = net.ParseIP("192.168.1.104")
remoteaddr.Port = 5000
if localaddr.IP == nil || remoteaddr.IP == nil {
fmt.Println("error")
}
if _, err := net.DialTCP("tcp", &localaddr, &remoteaddr); err != nil {
fmt.Println(err)
}
fmt.Println("End")
}
If the function specify local IP address, it always reports a run time error "dial tcp 192.168.1.104:5000: An invalid argument was supplied." I'm confused, should it always be a nil for local IP address ?
go version : 1.1 Beta
OS: Win7 64bit
Tried in go 1.0.3, it seemed OK
Go's net package, like most such implementations, recognizes port-only syntax for connecting to localhost:
:5000
is equivalent to
<my-ip-address>:5000
Thus, you can do:
net.Dial("tcp", ":5000")
No, it is ok to have laddr argument specified in DialTCP. The problem is that the specified port (6000) is outside of default Win7 dynamic port range and couldn't be used for outgoing connection. It works on Linux and Mac, actually (if you don't forget to change the IP address to one of your own system).

Resources