func modify(config *configs.Config, context *cli.Context) { config.ParentDeathSignal = context.Int("parent-death-signal") config.Readonlyfs = context.Bool("read-only") config.Cgroups.CpusetCpus = context.String("cpuset-cpus") config.Cgroups.CpusetMems = context.String("cpuset-mems") config.Cgroups.CpuShares = int64(context.Int("cpushares")) config.Cgroups.Memory = int64(context.Int("memory-limit")) config.Cgroups.MemorySwap = int64(context.Int("memory-swap")) config.AppArmorProfile = context.String("apparmor-profile") config.ProcessLabel = context.String("process-label") config.MountLabel = context.String("mount-label") rootfs := context.String("rootfs") if rootfs != "" { config.Rootfs = rootfs } userns_uid := context.Int("userns-root-uid") if userns_uid != 0 { config.Namespaces.Add(configs.NEWUSER, "") config.UidMappings = []configs.IDMap{ {ContainerID: 0, HostID: userns_uid, Size: 1}, {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, } config.GidMappings = []configs.IDMap{ {ContainerID: 0, HostID: userns_uid, Size: 1}, {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, } for _, node := range config.Devices { node.Uid = uint32(userns_uid) node.Gid = uint32(userns_uid) } } for _, rawBind := range context.StringSlice("bind") { mount := &configs.Mount{ Device: "bind", Flags: syscall.MS_BIND | syscall.MS_REC, } parts := strings.SplitN(rawBind, ":", 3) switch len(parts) { default: logrus.Fatalf("invalid bind mount %s", rawBind) case 2: mount.Source, mount.Destination = parts[0], parts[1] case 3: mount.Source, mount.Destination = parts[0], parts[1] switch parts[2] { case "ro": mount.Flags |= syscall.MS_RDONLY case "rw": default: logrus.Fatalf("invalid bind mount mode %s", parts[2]) } } config.Mounts = append(config.Mounts, mount) } for _, tmpfs := range context.StringSlice("tmpfs") { config.Mounts = append(config.Mounts, &configs.Mount{ Device: "tmpfs", Destination: tmpfs, Flags: syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV, }) } for flag, value := range map[string]configs.NamespaceType{ "net": configs.NEWNET, "mnt": configs.NEWNS, "pid": configs.NEWPID, "ipc": configs.NEWIPC, "uts": configs.NEWUTS, } { switch v := context.String(flag); v { case "host": config.Namespaces.Remove(value) case "", "private": if !config.Namespaces.Contains(value) { config.Namespaces.Add(value, "") } if flag == "net" { config.Networks = []*configs.Network{ { Type: "loopback", Address: "127.0.0.1/0", Gateway: "localhost", }, } } if flag == "uts" { config.Hostname = context.String("hostname") } default: config.Namespaces.Remove(value) config.Namespaces.Add(value, v) } } if bridge := context.String("veth-bridge"); bridge != "" { hostName, err := utils.GenerateRandomName("veth", 7) if err != nil { logrus.Fatal(err) } network := &configs.Network{ Type: "veth", Name: "eth0", Bridge: bridge, Address: context.String("veth-address"), Gateway: context.String("veth-gateway"), Mtu: context.Int("veth-mtu"), HostInterfaceName: hostName, } config.Networks = append(config.Networks, network) } }
// TODO(vmarmol): Deprecate over time as old Dockers are phased out. func ReadConfig(dockerRoot, dockerRun, containerID string) (*configs.Config, error) { // Try using the new config if it is available. configPath := configPath(dockerRun, containerID) if utils.FileExists(configPath) { out, err := ioutil.ReadFile(configPath) if err != nil { return nil, err } var state libcontainer.State err = json.Unmarshal(out, &state) if err != nil { glog.Errorf("Unmarshal failure for: \n\n%v\n", string(out)) return nil, err } return &state.Config, nil } // Fallback to reading the old config which is comprised of the state and config files. oldConfigPath := oldConfigPath(dockerRoot, containerID) out, err := ioutil.ReadFile(oldConfigPath) if err != nil { glog.Errorf("Unmarshal failure for: \n\n%v\n", string(out)) return nil, err } // Try reading the preAPIConfig. var config preAPIConfig err = json.Unmarshal(out, &config) if err != nil { // Try to parse the old pre-API config. The main difference is that namespaces used to be a map, now it is a slice of structs. // The JSON marshaler will use the non-nested field before the nested one. type oldLibcontainerConfig struct { preAPIConfig OldNamespaces map[string]bool `json:"namespaces,omitempty"` } var oldConfig oldLibcontainerConfig err2 := json.Unmarshal(out, &oldConfig) if err2 != nil { // Use original error. return nil, err } // Translate the old pre-API config into the new config. config = oldConfig.preAPIConfig for ns := range oldConfig.OldNamespaces { config.Namespaces = append(config.Namespaces, configs.Namespace{ Type: configs.NamespaceType(ns), }) } } // Read the old state file as well. state, err := readState(dockerRoot, containerID) if err != nil { return nil, err } // Convert preAPIConfig + old state file to Config. // This only converts some of the fields, the ones we use. // You may need to add fields if the one you're interested in is not available. var result configs.Config result.Cgroups = new(configs.Cgroup) result.Rootfs = config.RootFs result.Hostname = config.Hostname result.Namespaces = config.Namespaces result.Capabilities = config.Capabilities for _, net := range config.Networks { n := &configs.Network{ Name: state.NetworkState.VethChild, Bridge: net.Bridge, MacAddress: net.MacAddress, Address: net.Address, Gateway: net.Gateway, IPv6Address: net.IPv6Address, IPv6Gateway: net.IPv6Gateway, HostInterfaceName: state.NetworkState.VethHost, } result.Networks = append(result.Networks, n) } result.Routes = config.Routes if config.Cgroups != nil { result.Cgroups = config.Cgroups } return &result, nil }