1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/libnetwork/endpoint.go
Alessandro Boch 0d3ad0eaee Control scope of JoinOption functions
ISSUE:
- JoinOption type takes the exported interface Endpoint as parameter.
  This does not allows libnetwork to control the setter functions
  which will be executed by processOptions(). Client can now craft
  any func (e Endpoint), pass it to Endpoint.Join() and have it executed.
  Beside the fact this allows the client to shot himself in the foot,
  there seem not to be a real need in having the JoinOption take the
  Endpoint interface as parameter.

CHANGE:
- Changing the JoinOption signature to take a pointer to the unexported
  endpoint structure. So now libnetwork is the only one that can define
  the Join() method's options setter functions via the self referenced
  JoinOption[...] functions.

Signed-off-by: Alessandro Boch <aboch@docker.com>
2015-04-30 10:49:31 -07:00

262 lines
5.6 KiB
Go

package libnetwork
import (
"os"
"path/filepath"
"github.com/docker/docker/pkg/etchosts"
"github.com/docker/libnetwork/sandbox"
"github.com/docker/libnetwork/types"
)
// Endpoint represents a logical connection between a network and a sandbox.
type Endpoint interface {
// A system generated id for this endpoint.
ID() string
// Name returns the name of this endpoint.
Name() string
// Network returns the name of the network to which this endpoint is attached.
Network() string
// Join creates a new sandbox for the given container ID and populates the
// network resources allocated for the endpoint and joins the sandbox to
// the endpoint. It returns the sandbox key to the caller
Join(containerID string, options ...JoinOption) (*ContainerData, error)
// Leave removes the sandbox associated with container ID and detaches
// the network resources populated in the sandbox
Leave(containerID string) error
// SandboxInfo returns the sandbox information for this endpoint.
SandboxInfo() *sandbox.Info
// Delete and detaches this endpoint from the network.
Delete() error
}
// ContainerData is a set of data returned when a container joins an endpoint.
type ContainerData struct {
SandboxKey string
HostsPath string
}
// JoinOption is a option setter function type used to pass varios options to
// endpoint Join method. The various setter functions of type JoinOption are
// provided by libnetwork, they look like JoinOption[...](...)
type JoinOption func(ep *endpoint)
type containerConfig struct {
Hostname string
Domainname string
}
type containerInfo struct {
ID string
Config containerConfig
Data ContainerData
}
type endpoint struct {
name string
id types.UUID
network *network
sandboxInfo *sandbox.Info
sandBox sandbox.Sandbox
container *containerInfo
}
const prefix = "/var/lib/docker/network/files"
func (ep *endpoint) ID() string {
return string(ep.id)
}
func (ep *endpoint) Name() string {
return ep.name
}
func (ep *endpoint) Network() string {
return ep.network.name
}
func (ep *endpoint) SandboxInfo() *sandbox.Info {
if ep.sandboxInfo == nil {
return nil
}
return ep.sandboxInfo.GetCopy()
}
func createBasePath(dir string) error {
err := os.MkdirAll(dir, 0644)
if err != nil && !os.IsExist(err) {
return err
}
return nil
}
func createHostsFile(path string) error {
var f *os.File
dir, _ := filepath.Split(path)
err := createBasePath(dir)
if err != nil {
return err
}
f, err = os.Create(path)
if err == nil {
f.Close()
}
return err
}
func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerData, error) {
var err error
if containerID == "" {
return nil, InvalidContainerIDError(containerID)
}
if ep.container != nil {
return nil, ErrInvalidJoin
}
ep.container = &containerInfo{}
defer func() {
if err != nil {
ep.container = nil
}
}()
if options != nil {
ep.processOptions(options...)
}
ep.container.Data.HostsPath = prefix + "/" + containerID + "/hosts"
err = createHostsFile(ep.container.Data.HostsPath)
if err != nil {
return nil, err
}
err = ep.buildHostsFiles()
if err != nil {
return nil, err
}
sboxKey := sandbox.GenerateKey(containerID)
sb, err := ep.network.ctrlr.sandboxAdd(sboxKey)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
ep.network.ctrlr.sandboxRm(sboxKey)
}
}()
sinfo := ep.SandboxInfo()
if sinfo != nil {
for _, i := range sinfo.Interfaces {
err = sb.AddInterface(i)
if err != nil {
return nil, err
}
}
err = sb.SetGateway(sinfo.Gateway)
if err != nil {
return nil, err
}
err = sb.SetGatewayIPv6(sinfo.GatewayIPv6)
if err != nil {
return nil, err
}
}
ep.container.ID = containerID
ep.container.Data.SandboxKey = sb.Key()
cData := ep.container.Data
return &cData, nil
}
func (ep *endpoint) Leave(containerID string) error {
if ep.container == nil || ep.container.ID == "" ||
containerID == "" || ep.container.ID != containerID {
return InvalidContainerIDError(containerID)
}
ep.network.ctrlr.sandboxRm(sandbox.GenerateKey(containerID))
ep.container = nil
return nil
}
func (ep *endpoint) Delete() error {
var err error
n := ep.network
n.Lock()
_, ok := n.endpoints[ep.id]
if !ok {
n.Unlock()
return &UnknownEndpointError{name: ep.name, id: string(ep.id)}
}
delete(n.endpoints, ep.id)
n.Unlock()
defer func() {
if err != nil {
n.Lock()
n.endpoints[ep.id] = ep
n.Unlock()
}
}()
err = n.driver.DeleteEndpoint(n.id, ep.id)
return err
}
func (ep *endpoint) buildHostsFiles() error {
var extraContent []etchosts.Record
name := ep.container.Config.Hostname
if ep.container.Config.Domainname != "" {
name = name + "." + ep.container.Config.Domainname
}
IP := ""
if ep.sandboxInfo != nil && ep.sandboxInfo.Interfaces[0] != nil &&
ep.sandboxInfo.Interfaces[0].Address != nil {
IP = ep.sandboxInfo.Interfaces[0].Address.IP.String()
}
return etchosts.Build(ep.container.Data.HostsPath, IP, ep.container.Config.Hostname,
ep.container.Config.Domainname, extraContent)
}
// JoinOptionHostname function returns an option setter for hostname option to
// be passed to endpoint Join method.
func JoinOptionHostname(name string) JoinOption {
return func(ep *endpoint) {
ep.container.Config.Hostname = name
}
}
// JoinOptionDomainname function returns an option setter for domainname option to
// be passed to endpoint Join method.
func JoinOptionDomainname(name string) JoinOption {
return func(ep *endpoint) {
ep.container.Config.Domainname = name
}
}
func (ep *endpoint) processOptions(options ...JoinOption) {
for _, opt := range options {
opt(ep)
}
}