github.com/rentongzhang/docker@v1.8.2-rc1/daemon/execdriver/native/create.go (about) 1 // +build linux,cgo 2 3 package native 4 5 import ( 6 "errors" 7 "fmt" 8 "net" 9 "strings" 10 "syscall" 11 12 "github.com/docker/docker/daemon/execdriver" 13 "github.com/opencontainers/runc/libcontainer/apparmor" 14 "github.com/opencontainers/runc/libcontainer/configs" 15 "github.com/opencontainers/runc/libcontainer/devices" 16 "github.com/opencontainers/runc/libcontainer/utils" 17 ) 18 19 // createContainer populates and configures the container type with the 20 // data provided by the execdriver.Command 21 func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) { 22 container := execdriver.InitContainer(c) 23 24 if err := d.createIpc(container, c); err != nil { 25 return nil, err 26 } 27 28 if err := d.createPid(container, c); err != nil { 29 return nil, err 30 } 31 32 if err := d.createUTS(container, c); err != nil { 33 return nil, err 34 } 35 36 if err := d.createNetwork(container, c); err != nil { 37 return nil, err 38 } 39 40 if c.ProcessConfig.Privileged { 41 if !container.Readonlyfs { 42 // clear readonly for /sys 43 for i := range container.Mounts { 44 if container.Mounts[i].Destination == "/sys" { 45 container.Mounts[i].Flags &= ^syscall.MS_RDONLY 46 } 47 } 48 container.ReadonlyPaths = nil 49 } 50 51 // clear readonly for cgroup 52 for i := range container.Mounts { 53 if container.Mounts[i].Device == "cgroup" { 54 container.Mounts[i].Flags &= ^syscall.MS_RDONLY 55 } 56 } 57 58 container.MaskPaths = nil 59 if err := d.setPrivileged(container); err != nil { 60 return nil, err 61 } 62 } else { 63 if err := d.setCapabilities(container, c); err != nil { 64 return nil, err 65 } 66 } 67 68 container.AdditionalGroups = c.GroupAdd 69 70 if c.AppArmorProfile != "" { 71 container.AppArmorProfile = c.AppArmorProfile 72 } 73 74 if err := execdriver.SetupCgroups(container, c); err != nil { 75 return nil, err 76 } 77 78 if container.Readonlyfs { 79 for i := range container.Mounts { 80 switch container.Mounts[i].Destination { 81 case "/proc", "/dev", "/dev/pts": 82 continue 83 } 84 container.Mounts[i].Flags |= syscall.MS_RDONLY 85 } 86 87 /* These paths must be remounted as r/o */ 88 container.ReadonlyPaths = append(container.ReadonlyPaths, "/dev") 89 } 90 91 if err := d.setupMounts(container, c); err != nil { 92 return nil, err 93 } 94 95 d.setupLabels(container, c) 96 d.setupRlimits(container, c) 97 return container, nil 98 } 99 100 func generateIfaceName() (string, error) { 101 for i := 0; i < 10; i++ { 102 name, err := utils.GenerateRandomName("veth", 7) 103 if err != nil { 104 continue 105 } 106 if _, err := net.InterfaceByName(name); err != nil { 107 if strings.Contains(err.Error(), "no such") { 108 return name, nil 109 } 110 return "", err 111 } 112 } 113 return "", errors.New("Failed to find name for new interface") 114 } 115 116 func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error { 117 if c.Network == nil { 118 return nil 119 } 120 if c.Network.ContainerID != "" { 121 d.Lock() 122 active := d.activeContainers[c.Network.ContainerID] 123 d.Unlock() 124 125 if active == nil { 126 return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) 127 } 128 129 state, err := active.State() 130 if err != nil { 131 return err 132 } 133 134 container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET]) 135 return nil 136 } 137 138 if c.Network.NamespacePath == "" { 139 return fmt.Errorf("network namespace path is empty") 140 } 141 142 container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) 143 return nil 144 } 145 146 func (d *driver) createIpc(container *configs.Config, c *execdriver.Command) error { 147 if c.Ipc.HostIpc { 148 container.Namespaces.Remove(configs.NEWIPC) 149 return nil 150 } 151 152 if c.Ipc.ContainerID != "" { 153 d.Lock() 154 active := d.activeContainers[c.Ipc.ContainerID] 155 d.Unlock() 156 157 if active == nil { 158 return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID) 159 } 160 161 state, err := active.State() 162 if err != nil { 163 return err 164 } 165 container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC]) 166 } 167 168 return nil 169 } 170 171 func (d *driver) createPid(container *configs.Config, c *execdriver.Command) error { 172 if c.Pid.HostPid { 173 container.Namespaces.Remove(configs.NEWPID) 174 return nil 175 } 176 177 return nil 178 } 179 180 func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) error { 181 if c.UTS.HostUTS { 182 container.Namespaces.Remove(configs.NEWUTS) 183 container.Hostname = "" 184 return nil 185 } 186 187 return nil 188 } 189 190 func (d *driver) setPrivileged(container *configs.Config) (err error) { 191 container.Capabilities = execdriver.GetAllCapabilities() 192 container.Cgroups.AllowAllDevices = true 193 194 hostDevices, err := devices.HostDevices() 195 if err != nil { 196 return err 197 } 198 container.Devices = hostDevices 199 200 if apparmor.IsEnabled() { 201 container.AppArmorProfile = "unconfined" 202 } 203 return nil 204 } 205 206 func (d *driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) { 207 container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) 208 return err 209 } 210 211 func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) { 212 if c.Resources == nil { 213 return 214 } 215 216 for _, rlimit := range c.Resources.Rlimits { 217 container.Rlimits = append(container.Rlimits, configs.Rlimit{ 218 Type: rlimit.Type, 219 Hard: rlimit.Hard, 220 Soft: rlimit.Soft, 221 }) 222 } 223 } 224 225 func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error { 226 userMounts := make(map[string]struct{}) 227 for _, m := range c.Mounts { 228 userMounts[m.Destination] = struct{}{} 229 } 230 231 // Filter out mounts that are overriden by user supplied mounts 232 var defaultMounts []*configs.Mount 233 _, mountDev := userMounts["/dev"] 234 for _, m := range container.Mounts { 235 if _, ok := userMounts[m.Destination]; !ok { 236 if mountDev && strings.HasPrefix(m.Destination, "/dev/") { 237 continue 238 } 239 defaultMounts = append(defaultMounts, m) 240 } 241 } 242 container.Mounts = defaultMounts 243 244 for _, m := range c.Mounts { 245 flags := syscall.MS_BIND | syscall.MS_REC 246 if !m.Writable { 247 flags |= syscall.MS_RDONLY 248 } 249 if m.Slave { 250 flags |= syscall.MS_SLAVE 251 } 252 container.Mounts = append(container.Mounts, &configs.Mount{ 253 Source: m.Source, 254 Destination: m.Destination, 255 Device: "bind", 256 Flags: flags, 257 }) 258 } 259 return nil 260 } 261 262 func (d *driver) setupLabels(container *configs.Config, c *execdriver.Command) { 263 container.ProcessLabel = c.ProcessLabel 264 container.MountLabel = c.MountLabel 265 }