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:
Guillaume J. Charmes 2014-01-13 18:36:59 -08:00 committed by Michael Crosby
parent d3bae131d6
commit f7684ea7f6
7 changed files with 273 additions and 226 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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
View 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 ""
}

View File

@ -1,4 +1,4 @@
package sysinit
package lxc
func setHostname(hostname string) error {
panic("Not supported on darwin")

View File

@ -1,4 +1,4 @@
package sysinit
package lxc
import (
"syscall"

View File

@ -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 {