forked from AliyunContainerService/pouch
/
server.go
124 lines (110 loc) · 2.95 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package server
import (
"crypto/tls"
"fmt"
"net"
"net/http"
"os"
"strings"
"sync"
"syscall"
"github.com/alibaba/pouch/apis/plugins"
"github.com/alibaba/pouch/client"
"github.com/alibaba/pouch/daemon/config"
"github.com/alibaba/pouch/daemon/mgr"
"github.com/sirupsen/logrus"
)
// Server is a http server which serves restful api to client.
type Server struct {
Config *config.Config
ContainerMgr mgr.ContainerMgr
SystemMgr mgr.SystemMgr
ImageMgr mgr.ImageMgr
VolumeMgr mgr.VolumeMgr
NetworkMgr mgr.NetworkMgr
listeners []net.Listener
ContainerPlugin plugins.ContainerPlugin
ManagerWhiteList map[string]struct{}
lock sync.RWMutex
}
// Start setup route table and listen to specified address which currently only supports unix socket and tcp address.
func (s *Server) Start() (err error) {
router := initRoute(s)
errCh := make(chan error)
defer func() {
if err != nil {
for _, one := range s.listeners {
one.Close()
}
}
}()
var tlsConfig *tls.Config
if s.Config.TLS.Key != "" && s.Config.TLS.Cert != "" {
tlsConfig, err = client.GenTLSConfig(s.Config.TLS.Key, s.Config.TLS.Cert, s.Config.TLS.CA)
if err != nil {
return err
}
if s.Config.TLS.VerifyRemote {
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
SetupManagerWhitelist(s)
}
for _, one := range s.Config.Listen {
l, err := getListener(one, tlsConfig)
if err != nil {
return err
}
logrus.Infof("start to listen to: %s", one)
s.listeners = append(s.listeners, l)
go func(l net.Listener) {
errCh <- http.Serve(l, router)
}(l)
}
// not error, will block and run forever.
return <-errCh
}
// SetupManagerWhitelist enables users to setup which common name can access this server
func SetupManagerWhitelist(server *Server) {
if server.Config.TLS.ManagerWhiteList != "" {
server.lock.Lock()
defer server.lock.Unlock()
arr := strings.Split(server.Config.TLS.ManagerWhiteList, ",")
server.ManagerWhiteList = make(map[string]struct{}, len(arr))
for _, cn := range arr {
server.ManagerWhiteList[cn] = struct{}{}
}
}
}
// Stop will shutdown http server by closing all listeners.
func (s *Server) Stop() error {
for _, one := range s.listeners {
one.Close()
}
return nil
}
func getListener(addr string, tlsConfig *tls.Config) (net.Listener, error) {
addrParts := strings.SplitN(addr, "://", 2)
if len(addrParts) != 2 {
return nil, fmt.Errorf("invalid listening address: %s", addr)
}
switch addrParts[0] {
case "tcp":
l, err := net.Listen("tcp", addrParts[1])
if err != nil {
return l, err
}
if tlsConfig != nil {
l = tls.NewListener(l, tlsConfig)
}
return l, err
case "unix":
if err := syscall.Unlink(addrParts[1]); err != nil && !os.IsNotExist(err) {
return nil, err
}
mask := syscall.Umask(0777)
defer syscall.Umask(mask)
return net.Listen("unix", addrParts[1])
default:
return nil, fmt.Errorf("only unix socket or tcp address is support")
}
}