mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Move docker init into drivers functions
Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume.charmes@docker.com> (github: creack) Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume.charmes@docker.com> (github: crosbymichael)
This commit is contained in:
parent
d3bae131d6
commit
f7684ea7f6
7 changed files with 273 additions and 226 deletions
|
@ -2,9 +2,29 @@ package chroot
|
|||
|
||||
import (
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/mount"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const DriverName = "chroot"
|
||||
|
||||
func init() {
|
||||
execdriver.RegisterDockerInitFct(DriverName, func(args *execdriver.DockerInitArgs) error {
|
||||
if err := mount.ForceMount("proc", "proc", "proc", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
defer mount.ForceUnmount("proc")
|
||||
cmd := exec.Command(args.Args[0], args.Args[1:]...)
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
return cmd.Run()
|
||||
})
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
}
|
||||
|
||||
|
@ -13,7 +33,7 @@ func NewDriver() (*driver, error) {
|
|||
}
|
||||
|
||||
func (d *driver) Name() string {
|
||||
return "chroot"
|
||||
return DriverName
|
||||
}
|
||||
|
||||
func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
|
||||
|
|
|
@ -7,11 +7,49 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrNotRunning = errors.New("Process could not be started")
|
||||
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
|
||||
ErrNotRunning = errors.New("Process could not be started")
|
||||
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
|
||||
ErrDriverAlreadyRegistered = errors.New("A driver already registered this docker init function")
|
||||
ErrDriverNotFound = errors.New("The requested docker init has not been found")
|
||||
)
|
||||
|
||||
type StartCallback func(*Process)
|
||||
var dockerInitFcts map[string]DockerInitFct
|
||||
|
||||
type (
|
||||
StartCallback func(*Process)
|
||||
DockerInitFct func(i *DockerInitArgs) error
|
||||
)
|
||||
|
||||
func RegisterDockerInitFct(name string, fct DockerInitFct) error {
|
||||
if dockerInitFcts == nil {
|
||||
dockerInitFcts = make(map[string]DockerInitFct)
|
||||
}
|
||||
if _, ok := dockerInitFcts[name]; ok {
|
||||
return ErrDriverAlreadyRegistered
|
||||
}
|
||||
dockerInitFcts[name] = fct
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDockerInitFct(name string) (DockerInitFct, error) {
|
||||
fct, ok := dockerInitFcts[name]
|
||||
if !ok {
|
||||
return nil, ErrDriverNotFound
|
||||
}
|
||||
return fct, nil
|
||||
}
|
||||
|
||||
type DockerInitArgs struct {
|
||||
User string
|
||||
Gateway string
|
||||
Ip string
|
||||
WorkDir string
|
||||
Privileged bool
|
||||
Env []string
|
||||
Args []string
|
||||
Mtu int
|
||||
Driver string
|
||||
}
|
||||
|
||||
type Driver interface {
|
||||
Run(c *Process, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
|
||||
|
|
|
@ -5,14 +5,50 @@ import (
|
|||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DriverName = "lxc"
|
||||
|
||||
func init() {
|
||||
execdriver.RegisterDockerInitFct(DriverName, func(args *execdriver.DockerInitArgs) error {
|
||||
if err := setupHostname(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setupNetworking(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setupCapabilities(args); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupWorkingDirectory(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := changeUser(args); err != nil {
|
||||
return err
|
||||
}
|
||||
path, err := exec.LookPath(args.Args[0])
|
||||
if err != nil {
|
||||
log.Printf("Unable to locate %v", args.Args[0])
|
||||
os.Exit(127)
|
||||
}
|
||||
if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
panic("Unreachable")
|
||||
})
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
root string // root path for the driver to use
|
||||
apparmor bool
|
||||
|
@ -32,7 +68,7 @@ func NewDriver(root string, apparmor bool) (*driver, error) {
|
|||
}
|
||||
|
||||
func (d *driver) Name() string {
|
||||
return "lxc"
|
||||
return DriverName
|
||||
}
|
||||
|
||||
func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
|
||||
|
|
153
execdriver/lxc/init.go
Normal file
153
execdriver/lxc/init.go
Normal file
|
@ -0,0 +1,153 @@
|
|||
package lxc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/pkg/netlink"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func setupHostname(args *execdriver.DockerInitArgs) error {
|
||||
hostname := getEnv(args, "HOSTNAME")
|
||||
if hostname == "" {
|
||||
return nil
|
||||
}
|
||||
return setHostname(hostname)
|
||||
}
|
||||
|
||||
// Setup networking
|
||||
func setupNetworking(args *execdriver.DockerInitArgs) error {
|
||||
if args.Ip != "" {
|
||||
// eth0
|
||||
iface, err := net.InterfaceByName("eth0")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(args.Ip)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkSetMTU(iface, args.Mtu); err != nil {
|
||||
return fmt.Errorf("Unable to set MTU: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
|
||||
// loopback
|
||||
iface, err = net.InterfaceByName("lo")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
}
|
||||
if args.Gateway != "" {
|
||||
gw := net.ParseIP(args.Gateway)
|
||||
if gw == nil {
|
||||
return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.Gateway)
|
||||
}
|
||||
|
||||
if err := netlink.AddDefaultGw(gw); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup working directory
|
||||
func setupWorkingDirectory(args *execdriver.DockerInitArgs) error {
|
||||
if args.WorkDir == "" {
|
||||
return nil
|
||||
}
|
||||
if err := syscall.Chdir(args.WorkDir); err != nil {
|
||||
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Takes care of dropping privileges to the desired user
|
||||
func changeUser(args *execdriver.DockerInitArgs) error {
|
||||
if args.User == "" {
|
||||
return nil
|
||||
}
|
||||
userent, err := utils.UserLookup(args.User)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find user %v: %v", args.User, err)
|
||||
}
|
||||
|
||||
uid, err := strconv.Atoi(userent.Uid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid uid: %v", userent.Uid)
|
||||
}
|
||||
gid, err := strconv.Atoi(userent.Gid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid gid: %v", userent.Gid)
|
||||
}
|
||||
|
||||
if err := syscall.Setgid(gid); err != nil {
|
||||
return fmt.Errorf("setgid failed: %v", err)
|
||||
}
|
||||
if err := syscall.Setuid(uid); err != nil {
|
||||
return fmt.Errorf("setuid failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupCapabilities(args *execdriver.DockerInitArgs) error {
|
||||
|
||||
if args.Privileged {
|
||||
return nil
|
||||
}
|
||||
|
||||
drop := []capability.Cap{
|
||||
capability.CAP_SETPCAP,
|
||||
capability.CAP_SYS_MODULE,
|
||||
capability.CAP_SYS_RAWIO,
|
||||
capability.CAP_SYS_PACCT,
|
||||
capability.CAP_SYS_ADMIN,
|
||||
capability.CAP_SYS_NICE,
|
||||
capability.CAP_SYS_RESOURCE,
|
||||
capability.CAP_SYS_TIME,
|
||||
capability.CAP_SYS_TTY_CONFIG,
|
||||
capability.CAP_MKNOD,
|
||||
capability.CAP_AUDIT_WRITE,
|
||||
capability.CAP_AUDIT_CONTROL,
|
||||
capability.CAP_MAC_OVERRIDE,
|
||||
capability.CAP_MAC_ADMIN,
|
||||
}
|
||||
|
||||
c, err := capability.NewPid(os.Getpid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Unset(capability.CAPS|capability.BOUNDS, drop...)
|
||||
|
||||
if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEnv(args *execdriver.DockerInitArgs, key string) string {
|
||||
for _, kv := range args.Env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if parts[0] == key && len(parts) == 2 {
|
||||
return parts[1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package sysinit
|
||||
package lxc
|
||||
|
||||
func setHostname(hostname string) error {
|
||||
panic("Not supported on darwin")
|
|
@ -1,4 +1,4 @@
|
|||
package sysinit
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"syscall"
|
|
@ -4,169 +4,17 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/mount"
|
||||
"github.com/dotcloud/docker/pkg/netlink"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type DockerInitArgs struct {
|
||||
user string
|
||||
gateway string
|
||||
ip string
|
||||
workDir string
|
||||
privileged bool
|
||||
env []string
|
||||
args []string
|
||||
mtu int
|
||||
driver string
|
||||
}
|
||||
|
||||
func setupHostname(args *DockerInitArgs) error {
|
||||
hostname := getEnv(args, "HOSTNAME")
|
||||
if hostname == "" {
|
||||
return nil
|
||||
}
|
||||
return setHostname(hostname)
|
||||
}
|
||||
|
||||
// Setup networking
|
||||
func setupNetworking(args *DockerInitArgs) error {
|
||||
if args.ip != "" {
|
||||
// eth0
|
||||
iface, err := net.InterfaceByName("eth0")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(args.ip)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkSetMTU(iface, args.mtu); err != nil {
|
||||
return fmt.Errorf("Unable to set MTU: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
|
||||
// loopback
|
||||
iface, err = net.InterfaceByName("lo")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
}
|
||||
if args.gateway != "" {
|
||||
gw := net.ParseIP(args.gateway)
|
||||
if gw == nil {
|
||||
return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.gateway)
|
||||
}
|
||||
|
||||
if err := netlink.AddDefaultGw(gw); err != nil {
|
||||
return fmt.Errorf("Unable to set up networking: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup working directory
|
||||
func setupWorkingDirectory(args *DockerInitArgs) error {
|
||||
if args.workDir == "" {
|
||||
return nil
|
||||
}
|
||||
if err := syscall.Chdir(args.workDir); err != nil {
|
||||
return fmt.Errorf("Unable to change dir to %v: %v", args.workDir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupMounts(args *DockerInitArgs) error {
|
||||
return mount.ForceMount("proc", "proc", "proc", "")
|
||||
}
|
||||
|
||||
// Takes care of dropping privileges to the desired user
|
||||
func changeUser(args *DockerInitArgs) error {
|
||||
if args.user == "" {
|
||||
return nil
|
||||
}
|
||||
userent, err := utils.UserLookup(args.user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find user %v: %v", args.user, err)
|
||||
}
|
||||
|
||||
uid, err := strconv.Atoi(userent.Uid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid uid: %v", userent.Uid)
|
||||
}
|
||||
gid, err := strconv.Atoi(userent.Gid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid gid: %v", userent.Gid)
|
||||
}
|
||||
|
||||
if err := syscall.Setgid(gid); err != nil {
|
||||
return fmt.Errorf("setgid failed: %v", err)
|
||||
}
|
||||
if err := syscall.Setuid(uid); err != nil {
|
||||
return fmt.Errorf("setuid failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupCapabilities(args *DockerInitArgs) error {
|
||||
|
||||
if args.privileged {
|
||||
return nil
|
||||
}
|
||||
|
||||
drop := []capability.Cap{
|
||||
capability.CAP_SETPCAP,
|
||||
capability.CAP_SYS_MODULE,
|
||||
capability.CAP_SYS_RAWIO,
|
||||
capability.CAP_SYS_PACCT,
|
||||
capability.CAP_SYS_ADMIN,
|
||||
capability.CAP_SYS_NICE,
|
||||
capability.CAP_SYS_RESOURCE,
|
||||
capability.CAP_SYS_TIME,
|
||||
capability.CAP_SYS_TTY_CONFIG,
|
||||
capability.CAP_MKNOD,
|
||||
capability.CAP_AUDIT_WRITE,
|
||||
capability.CAP_AUDIT_CONTROL,
|
||||
capability.CAP_MAC_OVERRIDE,
|
||||
capability.CAP_MAC_ADMIN,
|
||||
}
|
||||
|
||||
c, err := capability.NewPid(os.Getpid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Unset(capability.CAPS|capability.BOUNDS, drop...)
|
||||
|
||||
if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clear environment pollution introduced by lxc-start
|
||||
func setupEnv(args *DockerInitArgs) {
|
||||
func setupEnv(args *execdriver.DockerInitArgs) {
|
||||
os.Clearenv()
|
||||
for _, kv := range args.env {
|
||||
for _, kv := range args.Env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
parts = append(parts, "")
|
||||
|
@ -175,66 +23,18 @@ func setupEnv(args *DockerInitArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
func getEnv(args *DockerInitArgs, key string) string {
|
||||
for _, kv := range args.env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if parts[0] == key && len(parts) == 2 {
|
||||
return parts[1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func executeProgram(args *DockerInitArgs) error {
|
||||
func executeProgram(args *execdriver.DockerInitArgs) error {
|
||||
setupEnv(args)
|
||||
|
||||
if args.driver == "lxc" {
|
||||
if err := setupHostname(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setupNetworking(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setupCapabilities(args); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupWorkingDirectory(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := changeUser(args); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if args.driver == "chroot" {
|
||||
if err := setupMounts(args); err != nil {
|
||||
return err
|
||||
}
|
||||
defer mount.ForceUnmount("proc")
|
||||
}
|
||||
|
||||
path, err := exec.LookPath(args.args[0])
|
||||
dockerInitFct, err := execdriver.GetDockerInitFct(args.Driver)
|
||||
if err != nil {
|
||||
log.Printf("Unable to locate %v", args.args[0])
|
||||
os.Exit(127)
|
||||
panic(err)
|
||||
}
|
||||
return dockerInitFct(args)
|
||||
|
||||
if args.driver == "lxc" {
|
||||
if err := syscall.Exec(path, args.args, os.Environ()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if args.Driver == "lxc" {
|
||||
// Will never reach
|
||||
} else if args.driver == "chroot" {
|
||||
cmd := exec.Command(path, args.args[1:]...)
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
return cmd.Run()
|
||||
} else if args.Driver == "chroot" {
|
||||
}
|
||||
panic("Should not be here")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -271,16 +71,16 @@ func SysInit() {
|
|||
// Propagate the plugin-specific container env variable
|
||||
env = append(env, "container="+os.Getenv("container"))
|
||||
|
||||
args := &DockerInitArgs{
|
||||
user: *user,
|
||||
gateway: *gateway,
|
||||
ip: *ip,
|
||||
workDir: *workDir,
|
||||
privileged: *privileged,
|
||||
env: env,
|
||||
args: flag.Args(),
|
||||
mtu: *mtu,
|
||||
driver: *driver,
|
||||
args := &execdriver.DockerInitArgs{
|
||||
User: *user,
|
||||
Gateway: *gateway,
|
||||
Ip: *ip,
|
||||
WorkDir: *workDir,
|
||||
Privileged: *privileged,
|
||||
Env: env,
|
||||
Args: flag.Args(),
|
||||
Mtu: *mtu,
|
||||
Driver: *driver,
|
||||
}
|
||||
|
||||
if err := executeProgram(args); err != nil {
|
||||
|
|
Loading…
Add table
Reference in a new issue