mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 10:09:07 +00:00
vendor pinata specific tools for now, until they are standalone packages
Signed-off-by: Justin Cormack <justin.cormack@unikernel.com>
This commit is contained in:
parent
7858a234b7
commit
7b61863705
@ -37,4 +37,8 @@ RUN \
|
|||||||
rc-update add docker default && \
|
rc-update add docker default && \
|
||||||
ln -s /bin/busybox /init
|
ln -s /bin/busybox /init
|
||||||
|
|
||||||
|
# docker mac specific, and should be moved anyway
|
||||||
|
RUN mkdir /Mac /Socket
|
||||||
|
COPY packages/9pudc/9pudc packages/mdnstool/mdnstool /sbin/
|
||||||
|
|
||||||
CMD ["/bin/sh"]
|
CMD ["/bin/sh"]
|
||||||
|
@ -6,8 +6,12 @@ ETCFILES+=etc/init.d/chronyd
|
|||||||
|
|
||||||
initrd.img: Dockerfile mkinitrd.sh repositories $(ETCFILES)
|
initrd.img: Dockerfile mkinitrd.sh repositories $(ETCFILES)
|
||||||
rm -f initrd.img
|
rm -f initrd.img
|
||||||
|
$(MAKE) -C packages/9pudc
|
||||||
|
$(MAKE) -C packages/mdnstool
|
||||||
docker build -t moby:test .
|
docker build -t moby:test .
|
||||||
docker run -i moby:test /bin/mkinitrd.sh > $@
|
docker run -i moby:test /bin/mkinitrd.sh > $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f initrd.img
|
rm -f initrd.img
|
||||||
|
$(MAKE) -C packages/9pudc clean
|
||||||
|
$(MAKE) -C packages/mdnstool clean
|
||||||
|
10
alpine/packages/9pudc/Dockerfile
Normal file
10
alpine/packages/9pudc/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM golang:alpine
|
||||||
|
|
||||||
|
RUN apk update && apk upgrade && apk add git
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src/9pudc
|
||||||
|
WORKDIR /go/src/9pudc
|
||||||
|
|
||||||
|
COPY . /go/src/9pudc/
|
||||||
|
RUN go get
|
||||||
|
RUN go install
|
8
alpine/packages/9pudc/Makefile
Normal file
8
alpine/packages/9pudc/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
all: 9pudc
|
||||||
|
|
||||||
|
9pudc: Dockerfile main.go
|
||||||
|
docker build -t 9pudc:test .
|
||||||
|
docker run 9pudc:test cat /go/bin/9pudc > 9pudc
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f 9pudc
|
140
alpine/packages/9pudc/main.go
Normal file
140
alpine/packages/9pudc/main.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
path string
|
||||||
|
sock string
|
||||||
|
detach bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&path, "path", "/9puds", "path of the 9P-mounted Unix domain socket tree")
|
||||||
|
flag.StringVar(&sock, "sock", "/tmp/forwarded.sock", "path of the local Unix domain socket to forward to")
|
||||||
|
flag.BoolVar(&detach, "detach", false, "detach from terminal")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if detach {
|
||||||
|
logFile, err := os.Create("/var/log/9pudc.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to open log file", err)
|
||||||
|
}
|
||||||
|
log.SetOutput(logFile)
|
||||||
|
null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to open /dev/null", err)
|
||||||
|
}
|
||||||
|
fd := null.Fd()
|
||||||
|
syscall.Dup2(int(fd), int(os.Stdin.Fd()))
|
||||||
|
syscall.Dup2(int(fd), int(os.Stdout.Fd()))
|
||||||
|
syscall.Dup2(int(fd), int(os.Stderr.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsPath := path + "/events"
|
||||||
|
events, err := os.Open(eventsPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to open file", eventsPath, err)
|
||||||
|
}
|
||||||
|
// 512 bytes is easily big enough to read a whole connection id
|
||||||
|
buf := make([]byte, 512)
|
||||||
|
for {
|
||||||
|
n, err := events.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error reading events file", err)
|
||||||
|
}
|
||||||
|
id, err := strconv.Atoi(strings.TrimSpace(string(buf[0:n])))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to parse integer connection id", err)
|
||||||
|
}
|
||||||
|
go handleOne(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleOne(id int) {
|
||||||
|
log.Println(id, "handleOne")
|
||||||
|
readPath := fmt.Sprintf("%s/connections/%d/read", path, id)
|
||||||
|
// Remove will cause the server end to close
|
||||||
|
defer func(){
|
||||||
|
log.Println(id, "handleOne closing, removing", readPath)
|
||||||
|
os.Remove(readPath)
|
||||||
|
}()
|
||||||
|
|
||||||
|
read, err := os.Open(readPath)
|
||||||
|
if err != nil {
|
||||||
|
// Fatal because this is a bug in the server implementation
|
||||||
|
log.Fatalln("Failed to open read file", readPath, err)
|
||||||
|
}
|
||||||
|
defer read.Close()
|
||||||
|
|
||||||
|
var conn *net.UnixConn
|
||||||
|
// Cope with the server socket appearing up to 10s later
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
conn, err = net.DialUnix("unix", nil, &net.UnixAddr{sock, "unix"})
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// If the forwarding program has broken then close and continue
|
||||||
|
log.Println("Failed to connect to Unix domain socket after 10s", sock, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w := make(chan int64)
|
||||||
|
go func() {
|
||||||
|
writePath := fmt.Sprintf("%s/connections/%d/write", path, id)
|
||||||
|
write, err := os.OpenFile(writePath, os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
// Fatal because this is a bug in the server implementation
|
||||||
|
log.Fatalln("Failed to open write file", writePath, err)
|
||||||
|
}
|
||||||
|
log.Println(id, "copying from", sock, "to", writePath)
|
||||||
|
n, err := io.Copy(write, conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error copying from Unix domain socket to 9P", err)
|
||||||
|
}
|
||||||
|
log.Println(id, "wrote", n, "bytes to", writePath)
|
||||||
|
conn.CloseRead()
|
||||||
|
write.Close()
|
||||||
|
os.Remove(writePath)
|
||||||
|
w <- n
|
||||||
|
}()
|
||||||
|
|
||||||
|
totalRead := int64(0)
|
||||||
|
log.Println(id, "copying from", readPath, "to", sock)
|
||||||
|
for {
|
||||||
|
// EOF is used to signal a chunk/packet of data
|
||||||
|
n, err := io.Copy(conn, read)
|
||||||
|
totalRead = totalRead + n
|
||||||
|
log.Println(id, "copied a packet of size", n, "bytes from stream")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(id, "error copying from stream file to Unix domain socket:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
log.Println(id, "read zero-length chunk from stream file: treating as EOF")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.CloseWrite();
|
||||||
|
|
||||||
|
log.Println(id, "waiting for writer to close")
|
||||||
|
totalWritten := <-w
|
||||||
|
log.Println(id, "read", totalRead, "written", totalWritten)
|
||||||
|
}
|
3
alpine/packages/README.md
Normal file
3
alpine/packages/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
The directories below should be turned into proper packages, built from upstream.
|
||||||
|
|
||||||
|
Currently these are temporarily vendored from pinata.
|
1
alpine/packages/mdnstool/.gitignore
vendored
Normal file
1
alpine/packages/mdnstool/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
mdnstool
|
10
alpine/packages/mdnstool/Dockerfile
Normal file
10
alpine/packages/mdnstool/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM golang:alpine
|
||||||
|
|
||||||
|
RUN apk update && apk upgrade && apk add git
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src/mdnstool
|
||||||
|
WORKDIR /go/src/mdnstool
|
||||||
|
|
||||||
|
COPY . /go/src/mdnstool/
|
||||||
|
RUN go get
|
||||||
|
RUN go install
|
8
alpine/packages/mdnstool/Makefile
Normal file
8
alpine/packages/mdnstool/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
all: mdnstool
|
||||||
|
|
||||||
|
mdnstool: Dockerfile mdnstool.go mdnsmon/mdnsmon.go
|
||||||
|
docker build -t mdnstool:test .
|
||||||
|
docker run mdnstool:test cat /go/bin/mdnstool > mdnstool
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f mdnstool
|
31
alpine/packages/mdnstool/README.md
Normal file
31
alpine/packages/mdnstool/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Tool to monitor a network interface for IP changes and publish an mDNS service.
|
||||||
|
|
||||||
|
To publish `docker.local` and map it to the IP of interface `eth0`:
|
||||||
|
|
||||||
|
```
|
||||||
|
./mdnstool -if eth0
|
||||||
|
```
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage of ./mdnstool:
|
||||||
|
-hostname string
|
||||||
|
Hostname - must be FQDN and end with . (default "docker.local.")
|
||||||
|
-if string
|
||||||
|
Network interface to bind multicast listener to. This interface will be monitored for IP changes. (default "eth0")
|
||||||
|
-info string
|
||||||
|
TXT service description (default "Moby")
|
||||||
|
-instance string
|
||||||
|
Instance description (default "Moby")
|
||||||
|
-port int
|
||||||
|
Service port (default 22)
|
||||||
|
-service string
|
||||||
|
SRV service type (default "_ssh._tcp")
|
||||||
|
```
|
||||||
|
|
||||||
|
To build for Linux:
|
||||||
|
|
||||||
|
```
|
||||||
|
GOOS=linux GOARCH=386 go build -v
|
||||||
|
```
|
153
alpine/packages/mdnstool/mdnsmon/mdnsmon.go
Normal file
153
alpine/packages/mdnstool/mdnsmon/mdnsmon.go
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package mdnsmon
|
||||||
|
|
||||||
|
// mDNS server that publishes a service with the IP address(es) of a monitored network interface.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/mdns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MDNSServer struct {
|
||||||
|
service *mdns.MDNSService
|
||||||
|
iface *net.Interface
|
||||||
|
ip_updates chan []net.IP
|
||||||
|
shutdown chan int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServer creates a new mDNS service and server configuration.
|
||||||
|
func NewServer(hostname string, instance string, port int, srv string, info []string, iface *net.Interface) (*MDNSServer, error) {
|
||||||
|
service, err := mdns.NewMDNSService(instance, srv, "local.", hostname, port, []net.IP{net.ParseIP("0.0.0.0")}, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_updates := make(chan []net.IP)
|
||||||
|
shutdown := make(chan int)
|
||||||
|
|
||||||
|
return &MDNSServer{service: service, ip_updates: ip_updates, shutdown: shutdown, iface: iface}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getIPs gets a list of IP addresses from an interface
|
||||||
|
func getIPs(iface *net.Interface) []net.IP {
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to read interface address(es), error: %s", err)
|
||||||
|
return []net.IP{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ips []net.IP
|
||||||
|
for _, a := range addrs {
|
||||||
|
switch v := a.(type) {
|
||||||
|
case *net.IPNet:
|
||||||
|
if v.IP.To4() != nil { // Only support IPv4 for now
|
||||||
|
ips = append(ips, v.IP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MDNSServer) runServer() {
|
||||||
|
var server *mdns.Server
|
||||||
|
var err error
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if server != nil {
|
||||||
|
log.Println("Shutting down mDNS server...")
|
||||||
|
server.Shutdown()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case ips := <-m.ip_updates: // New IP set received, registering service
|
||||||
|
// Update service/zone record
|
||||||
|
m.service.IPs = ips
|
||||||
|
|
||||||
|
// Shutdown old mDNS server, if running
|
||||||
|
if server != nil {
|
||||||
|
log.Println("New configuration - shutting down mDNS server...")
|
||||||
|
server.Shutdown()
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
server = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if no IPs found
|
||||||
|
if len(ips) == 0 {
|
||||||
|
log.Println("No IP address. Waiting for IP to be configured.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the mDNS server
|
||||||
|
log.Println("Answering requests for IP(s) ", ips)
|
||||||
|
server, err = mdns.NewServer(&mdns.Config{Zone: m.service, Iface: m.iface})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
m.service.IPs = []net.IP{} // Reset IP set so we can automatically retry later
|
||||||
|
}
|
||||||
|
case <-m.shutdown:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isIPsequal compares to slices with IPs
|
||||||
|
func isIPsequal(a []net.IP, b []net.IP) bool {
|
||||||
|
if a == nil && b == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil && b != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if a != nil && b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, ip1 := range a {
|
||||||
|
match := false
|
||||||
|
for _, ip2 := range b {
|
||||||
|
if ip1.Equal(ip2) {
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if match == false { // if one ip from a is not in b, return false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the background mDNS server and starts monitoring the network interface for IP changes.
|
||||||
|
func (m *MDNSServer) Start() {
|
||||||
|
// Start background server
|
||||||
|
go m.runServer()
|
||||||
|
|
||||||
|
// Monitor interface for IP changes
|
||||||
|
for {
|
||||||
|
ips := getIPs(m.iface)
|
||||||
|
if !isIPsequal(ips, m.service.IPs) {
|
||||||
|
log.Println("IP configuration:", ips)
|
||||||
|
m.ip_updates <- ips
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO(magnuss) Monitor using netlink?
|
||||||
|
if len(ips) == 0 { // Sleep shorter if no IP found
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
} else {
|
||||||
|
time.Sleep(60 * time.Second) // Takes longer to react on IP change, but mDNS has TTL of 120 sec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown stops the background mDNS server and stops monitorint the network interface for IP changes.
|
||||||
|
func (m *MDNSServer) Shutdown() {
|
||||||
|
m.shutdown <- 0 // TODO(magnuss) Wait for mDNS to shutdown
|
||||||
|
}
|
57
alpine/packages/mdnstool/mdnstool.go
Normal file
57
alpine/packages/mdnstool/mdnstool.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// CLI tool for mDNSmon. Monitors a network interface for IP changes and re-publishes the mDNS service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"mdnstool/mdnsmon"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
hostname := flag.String("hostname", "docker.local.", "Hostname - must be FQDN and end with .")
|
||||||
|
instance := flag.String("instance", "Moby", "Instance description")
|
||||||
|
port := flag.Int("port", 22, "Service port")
|
||||||
|
srv := flag.String("service", "_ssh._tcp", "SRV service type")
|
||||||
|
info := flag.String("info", "Moby", "TXT service description")
|
||||||
|
iface_name := flag.String("if", "eth0", "Network interface to bind multicast listener to. This interface will be monitored for IP changes.")
|
||||||
|
detach := flag.Bool("detach", false, "Detach from terminal")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Deatch from terminal (based on code from 9pudc)
|
||||||
|
if *detach {
|
||||||
|
logFile, err := os.Create("/var/log/mdnstool.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to open log file", err)
|
||||||
|
}
|
||||||
|
log.SetOutput(logFile)
|
||||||
|
null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to open /dev/null", err)
|
||||||
|
}
|
||||||
|
fd := null.Fd()
|
||||||
|
syscall.Dup2(int(fd), int(os.Stdin.Fd()))
|
||||||
|
syscall.Dup2(int(fd), int(os.Stdout.Fd()))
|
||||||
|
syscall.Dup2(int(fd), int(os.Stderr.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
iface, err := net.InterfaceByName(*iface_name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := mdnsmon.NewServer(*hostname, *instance, *port, *srv, []string{*info}, iface)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go s.Start()
|
||||||
|
defer s.Shutdown()
|
||||||
|
select {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user