From 193767edd7feb8442b67da159e48654dc8fc71a9 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 29 Aug 2013 21:52:45 +0000 Subject: [PATCH] Add DaemonConfig Use a config type for accessing data Add bridgeiface name to config Add option to disable iptables --- api.go | 4 ++-- api_test.go | 6 ++++-- config.go | 12 ++++++++++++ docker/docker.go | 43 ++++++++++++++++++++++++++---------------- network.go | 49 ++++++++++++++++++++++++++---------------------- runtime.go | 38 +++++++++++++++++-------------------- runtime_test.go | 15 +++++++++------ server.go | 12 +++++------- utils_test.go | 6 +++++- 9 files changed, 108 insertions(+), 77 deletions(-) create mode 100644 config.go diff --git a/api.go b/api.go index bc0c43696..26a19529d 100644 --- a/api.go +++ b/api.go @@ -512,7 +512,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r return err } - if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) { + if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) { out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns)) config.Dns = defaultDns } @@ -973,7 +973,7 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s if err != nil { version = APIVERSION } - if srv.enableCors { + if srv.runtime.config.EnableCors { writeCorsHeaders(w, r) } diff --git a/api_test.go b/api_test.go index bcf662e9e..2d63f0ccd 100644 --- a/api_test.go +++ b/api_test.go @@ -1115,7 +1115,8 @@ func TestOptionsRoute(t *testing.T) { runtime := mkRuntime(t) defer nuke(runtime) - srv := &Server{runtime: runtime, enableCors: true} + runtime.config.EnableCors = true + srv := &Server{runtime: runtime} r := httptest.NewRecorder() router, err := createRouter(srv, false) @@ -1138,7 +1139,8 @@ func TestGetEnabledCors(t *testing.T) { runtime := mkRuntime(t) defer nuke(runtime) - srv := &Server{runtime: runtime, enableCors: true} + runtime.config.EnableCors = true + srv := &Server{runtime: runtime} r := httptest.NewRecorder() diff --git a/config.go b/config.go new file mode 100644 index 000000000..6d86535a6 --- /dev/null +++ b/config.go @@ -0,0 +1,12 @@ +package docker + +type DaemonConfig struct { + Pidfile string + GraphPath string + ProtoAddresses []string + AutoRestart bool + EnableCors bool + Dns []string + EnableIptables bool + BridgeIface string +} diff --git a/docker/docker.go b/docker/docker.go index 750d63c06..fb2f79013 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -37,6 +37,7 @@ func main() { flDns := flag.String("dns", "", "Set custom dns servers") flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)} flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use") + flEnableIptables := flag.Bool("iptables", true, "Disable iptables within docker") flag.Parse() if *flVersion { showVersion() @@ -49,10 +50,9 @@ func main() { flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost) } + bridge := docker.DefaultNetworkBridge if *bridgeName != "" { - docker.NetworkBridgeIface = *bridgeName - } else { - docker.NetworkBridgeIface = docker.DefaultNetworkBridge + bridge = *bridgeName } if *flDebug { os.Setenv("DEBUG", "1") @@ -64,7 +64,22 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, *flGraphPath, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil { + var dns []string + if *flDns != "" { + dns = []string{*flDns} + } + + config := &docker.DaemonConfig{ + Pidfile: *pidfile, + GraphPath: *flGraphPath, + AutoRestart: *flAutoRestart, + EnableCors: *flEnableCors, + Dns: dns, + EnableIptables: *flEnableIptables, + BridgeIface: bridge, + ProtoAddresses: flHosts, + } + if err := daemon(config); err != nil { log.Fatal(err) os.Exit(-1) } @@ -115,30 +130,26 @@ func removePidFile(pidfile string) { } } -func daemon(pidfile string, flGraphPath string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error { - if err := createPidFile(pidfile); err != nil { +func daemon(config *docker.DaemonConfig) error { + if err := createPidFile(config.Pidfile); err != nil { log.Fatal(err) } - defer removePidFile(pidfile) + defer removePidFile(config.Pidfile) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM)) go func() { sig := <-c log.Printf("Received signal '%v', exiting\n", sig) - removePidFile(pidfile) + removePidFile(config.Pidfile) os.Exit(0) }() - var dns []string - if flDns != "" { - dns = []string{flDns} - } - server, err := docker.NewServer(flGraphPath, autoRestart, enableCors, dns) + server, err := docker.NewServer(config) if err != nil { return err } - chErrors := make(chan error, len(protoAddrs)) - for _, protoAddr := range protoAddrs { + chErrors := make(chan error, len(config.ProtoAddresses)) + for _, protoAddr := range config.ProtoAddresses { protoAddrParts := strings.SplitN(protoAddr, "://", 2) if protoAddrParts[0] == "unix" { syscall.Unlink(protoAddrParts[1]) @@ -154,7 +165,7 @@ func daemon(pidfile string, flGraphPath string, protoAddrs []string, autoRestart chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true) }() } - for i := 0; i < len(protoAddrs); i += 1 { + for i := 0; i < len(config.ProtoAddresses); i += 1 { err := <-chErrors if err != nil { return err diff --git a/network.go b/network.go index e7973673b..7836f17ae 100644 --- a/network.go +++ b/network.go @@ -14,8 +14,6 @@ import ( "sync" ) -var NetworkBridgeIface string - const ( DefaultNetworkBridge = "docker0" DisableNetworkBridge = "none" @@ -113,7 +111,7 @@ func checkRouteOverlaps(routes string, dockerNetwork *net.IPNet) error { // CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`, // and attempts to configure it with an address which doesn't conflict with any other interface on the host. // If it can't find an address which doesn't conflict, it will return an error. -func CreateBridgeIface(ifaceName string) error { +func CreateBridgeIface(config *DaemonConfig) error { addrs := []string{ // Here we don't follow the convention of using the 1st IP of the range for the gateway. // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. @@ -152,23 +150,25 @@ func CreateBridgeIface(ifaceName string) error { } } if ifaceAddr == "" { - return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", ifaceName, ifaceName) + return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", config.BridgeIface, config.BridgeIface) } - utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr) + utils.Debugf("Creating bridge %s with network %s", config.BridgeIface, ifaceAddr) - if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil { + if output, err := ip("link", "add", config.BridgeIface, "type", "bridge"); err != nil { return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output) } - if output, err := ip("addr", "add", ifaceAddr, "dev", ifaceName); err != nil { + if output, err := ip("addr", "add", ifaceAddr, "dev", config.BridgeIface); err != nil { return fmt.Errorf("Unable to add private network: %s (%s)", err, output) } - if output, err := ip("link", "set", ifaceName, "up"); err != nil { + if output, err := ip("link", "set", config.BridgeIface, "up"); err != nil { return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output) } - if err := iptables.Raw("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr, - "!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil { - return fmt.Errorf("Unable to enable network bridge NAT: %s", err) + if config.EnableIptables { + if err := iptables.Raw("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr, + "!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil { + return fmt.Errorf("Unable to enable network bridge NAT: %s", err) + } } return nil } @@ -284,13 +284,18 @@ func (mapper *PortMapper) Unmap(port int, proto string) error { return nil } -func newPortMapper() (*PortMapper, error) { +func newPortMapper(config *DaemonConfig) (*PortMapper, error) { + // We can always try removing the iptables if err := iptables.RemoveExistingChain("DOCKER"); err != nil { return nil, err } - chain, err := iptables.NewChain("DOCKER", NetworkBridgeIface) - if err != nil { - return nil, fmt.Errorf("Failed to create DOCKER chain: %s", err) + var chain *iptables.Chain + if config.EnableIptables { + var err error + chain, err = iptables.NewChain("DOCKER", config.BridgeIface) + if err != nil { + return nil, fmt.Errorf("Failed to create DOCKER chain: %s", err) + } } mapper := &PortMapper{ @@ -633,22 +638,22 @@ func (manager *NetworkManager) Allocate() (*NetworkInterface, error) { return iface, nil } -func newNetworkManager(bridgeIface string) (*NetworkManager, error) { +func newNetworkManager(config *DaemonConfig) (*NetworkManager, error) { - if bridgeIface == DisableNetworkBridge { + if config.BridgeIface == DisableNetworkBridge { manager := &NetworkManager{ disabled: true, } return manager, nil } - addr, err := getIfaceAddr(bridgeIface) + addr, err := getIfaceAddr(config.BridgeIface) if err != nil { // If the iface is not found, try to create it - if err := CreateBridgeIface(bridgeIface); err != nil { + if err := CreateBridgeIface(config); err != nil { return nil, err } - addr, err = getIfaceAddr(bridgeIface) + addr, err = getIfaceAddr(config.BridgeIface) if err != nil { return nil, err } @@ -666,13 +671,13 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) { return nil, err } - portMapper, err := newPortMapper() + portMapper, err := newPortMapper(config) if err != nil { return nil, err } manager := &NetworkManager{ - bridgeIface: bridgeIface, + bridgeIface: config.BridgeIface, bridgeNetwork: network, ipAllocator: ipAllocator, tcpPortAllocator: tcpPortAllocator, diff --git a/runtime.go b/runtime.go index d77ecca72..349dacd91 100644 --- a/runtime.go +++ b/runtime.go @@ -24,7 +24,6 @@ type Capabilities struct { } type Runtime struct { - root string repository string containers *list.List networkManager *NetworkManager @@ -33,10 +32,9 @@ type Runtime struct { idIndex *utils.TruncIndex capabilities *Capabilities kernelVersion *utils.KernelVersionInfo - autoRestart bool volumes *Graph srv *Server - Dns []string + config *DaemonConfig } var sysInitPath string @@ -149,7 +147,7 @@ func (runtime *Runtime) Register(container *Container) error { } if !strings.Contains(string(output), "RUNNING") { utils.Debugf("Container %s was supposed to be running be is not.", container.ID) - if runtime.autoRestart { + if runtime.config.AutoRestart { utils.Debugf("Restarting") container.State.Ghost = false container.State.setStopped(0) @@ -335,18 +333,18 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) { return nil, err } - if len(config.Dns) == 0 && len(runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) { + if len(config.Dns) == 0 && len(runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) { //"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns - runtime.Dns = defaultDns + runtime.config.Dns = defaultDns } // If custom dns exists, then create a resolv.conf for the container - if len(config.Dns) > 0 || len(runtime.Dns) > 0 { + if len(config.Dns) > 0 || len(runtime.config.Dns) > 0 { var dns []string if len(config.Dns) > 0 { dns = config.Dns } else { - dns = runtime.Dns + dns = runtime.config.Dns } container.ResolvConfPath = path.Join(container.root, "resolv.conf") f, err := os.Create(container.ResolvConfPath) @@ -428,12 +426,11 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a } // FIXME: harmonize with NewGraph() -func NewRuntime(flGraphPath string, autoRestart bool, dns []string) (*Runtime, error) { - runtime, err := NewRuntimeFromDirectory(flGraphPath, autoRestart) +func NewRuntime(config *DaemonConfig) (*Runtime, error) { + runtime, err := NewRuntimeFromDirectory(config) if err != nil { return nil, err } - runtime.Dns = dns if k, err := utils.GetKernelVersion(); err != nil { log.Printf("WARNING: %s\n", err) @@ -447,34 +444,33 @@ func NewRuntime(flGraphPath string, autoRestart bool, dns []string) (*Runtime, e return runtime, nil } -func NewRuntimeFromDirectory(root string, autoRestart bool) (*Runtime, error) { - runtimeRepo := path.Join(root, "containers") +func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { + runtimeRepo := path.Join(config.GraphPath, "containers") if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) { return nil, err } - g, err := NewGraph(path.Join(root, "graph")) + g, err := NewGraph(path.Join(config.GraphPath, "graph")) if err != nil { return nil, err } - volumes, err := NewGraph(path.Join(root, "volumes")) + volumes, err := NewGraph(path.Join(config.GraphPath, "volumes")) if err != nil { return nil, err } - repositories, err := NewTagStore(path.Join(root, "repositories"), g) + repositories, err := NewTagStore(path.Join(config.GraphPath, "repositories"), g) if err != nil { return nil, fmt.Errorf("Couldn't create Tag store: %s", err) } - if NetworkBridgeIface == "" { - NetworkBridgeIface = DefaultNetworkBridge + if config.BridgeIface == "" { + config.BridgeIface = DefaultNetworkBridge } - netManager, err := newNetworkManager(NetworkBridgeIface) + netManager, err := newNetworkManager(config) if err != nil { return nil, err } runtime := &Runtime{ - root: root, repository: runtimeRepo, containers: list.New(), networkManager: netManager, @@ -482,8 +478,8 @@ func NewRuntimeFromDirectory(root string, autoRestart bool) (*Runtime, error) { repositories: repositories, idIndex: utils.NewTruncIndex(), capabilities: &Capabilities{}, - autoRestart: autoRestart, volumes: volumes, + config: config, } if err := runtime.restore(); err != nil { diff --git a/runtime_test.go b/runtime_test.go index f4f5d5af1..5cb360915 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -42,7 +42,7 @@ func nuke(runtime *Runtime) error { }(container) } wg.Wait() - return os.RemoveAll(runtime.root) + return os.RemoveAll(runtime.config.GraphPath) } func cleanup(runtime *Runtime) error { @@ -84,10 +84,13 @@ func init() { log.Fatal("docker tests need to be run as root") } - NetworkBridgeIface = unitTestNetworkBridge - // Make it our Store root - if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil { + config := &DaemonConfig{ + GraphPath: unitTestStoreBase, + AutoRestart: false, + BridgeIface: unitTestNetworkBridge, + } + if runtime, err := NewRuntimeFromDirectory(config); err != nil { panic(err) } else { globalRuntime = runtime @@ -96,7 +99,6 @@ func init() { // Create the "Server" srv := &Server{ runtime: globalRuntime, - enableCors: false, pullingPool: make(map[string]struct{}), pushingPool: make(map[string]struct{}), } @@ -456,7 +458,8 @@ func TestRestore(t *testing.T) { // Here are are simulating a docker restart - that is, reloading all containers // from scratch - runtime2, err := NewRuntimeFromDirectory(runtime1.root, false) + runtime1.config.AutoRestart = false + runtime2, err := NewRuntimeFromDirectory(runtime1.config) if err != nil { t.Fatal(err) } diff --git a/server.go b/server.go index 5bfbc9692..789d2aed1 100644 --- a/server.go +++ b/server.go @@ -102,7 +102,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error { } func (srv *Server) ImagesSearch(term string) ([]APISearch, error) { - r, err := registry.NewRegistry(srv.runtime.root, nil, srv.HTTPRequestFactory(nil)) + r, err := registry.NewRegistry(srv.runtime.config.GraphPath, nil, srv.HTTPRequestFactory(nil)) if err != nil { return nil, err } @@ -634,7 +634,7 @@ func (srv *Server) poolRemove(kind, key string) error { } func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig, metaHeaders map[string][]string, parallel bool) error { - r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory(metaHeaders)) + r, err := registry.NewRegistry(srv.runtime.config.GraphPath, authConfig, srv.HTTPRequestFactory(metaHeaders)) if err != nil { return err } @@ -843,7 +843,7 @@ func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFo out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(localName) - r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory(metaHeaders)) + r, err2 := registry.NewRegistry(srv.runtime.config.GraphPath, authConfig, srv.HTTPRequestFactory(metaHeaders)) if err2 != nil { return err2 } @@ -1299,17 +1299,16 @@ func (srv *Server) ContainerCopy(name string, resource string, out io.Writer) er } -func NewServer(flGraphPath string, autoRestart, enableCors bool, dns ListOpts) (*Server, error) { +func NewServer(config *DaemonConfig) (*Server, error) { if runtime.GOARCH != "amd64" { log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) } - runtime, err := NewRuntime(flGraphPath, autoRestart, dns) + runtime, err := NewRuntime(config) if err != nil { return nil, err } srv := &Server{ runtime: runtime, - enableCors: enableCors, pullingPool: make(map[string]struct{}), pushingPool: make(map[string]struct{}), events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events @@ -1347,7 +1346,6 @@ func (srv *Server) LogEvent(action, id, from string) { type Server struct { sync.Mutex runtime *Runtime - enableCors bool pullingPool map[string]struct{} pushingPool map[string]struct{} events []utils.JSONMessage diff --git a/utils_test.go b/utils_test.go index 740a5fc1b..2d05a37b9 100644 --- a/utils_test.go +++ b/utils_test.go @@ -42,7 +42,11 @@ func newTestRuntime() (*Runtime, error) { return nil, err } - runtime, err := NewRuntimeFromDirectory(root, false) + config := &DaemonConfig{ + GraphPath: root, + AutoRestart: false, + } + runtime, err := NewRuntimeFromDirectory(config) if err != nil { return nil, err }