mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
0d3ad0eaee
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>
262 lines
5.6 KiB
Go
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)
|
|
}
|
|
}
|