// processSetKeyReexec is a private function that must be called only on an reexec path // It expects 3 args { [0] = "libnetwork-setkey", [1] = <container-id>, [2] = <controller-id> } // It also expects libcontainer.State as a json string in <stdin> // Refer to https://github.com/opencontainers/runc/pull/160/ for more information func processSetKeyReexec() { var err error // Return a failure to the calling process via ExitCode defer func() { if err != nil { logrus.Fatalf("%v", err) } }() // expecting 3 args {[0]="libnetwork-setkey", [1]=<container-id>, [2]=<controller-id> } if len(os.Args) < 3 { err = fmt.Errorf("Re-exec expects 3 args, received : %d", len(os.Args)) return } containerID := os.Args[1] // We expect libcontainer.State as a json string in <stdin> stateBuf, err := ioutil.ReadAll(os.Stdin) if err != nil { return } var state libcontainer.State if err = json.Unmarshal(stateBuf, &state); err != nil { return } controllerID := os.Args[2] key := state.NamespacePaths[configs.NamespaceType("NEWNET")] err = SetExternalKey(controllerID, containerID, key) return }
func reexecSetKey(key string, containerID string, controllerID string) error { var ( state libcontainer.State b []byte err error ) state.NamespacePaths = make(map[configs.NamespaceType]string) state.NamespacePaths[configs.NamespaceType("NEWNET")] = key if b, err = json.Marshal(state); err != nil { return err } cmd := &exec.Cmd{ Path: reexec.Self(), Args: append([]string{"libnetwork-setkey"}, containerID, controllerID), Stdin: strings.NewReader(string(b)), Stdout: os.Stdout, Stderr: os.Stderr, } return cmd.Run() }
// 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 if err = json.Unmarshal(out, &state); err != nil { if _, ok := err.(*json.UnmarshalTypeError); ok { // Since some fields changes in Cgroup struct, it will be failed while unmarshalling to libcontainer.State struct. // This failure is caused by a change of runc(https://github.com/opencontainers/runc/commit/c6e406af243fab0c9636539c1cb5f4d60fe0787f). // If we encountered the UnmarshalTypeError, try to unmarshal it again to v1State struct and convert it. var state v1State err2 := json.Unmarshal(out, &state) if err2 != nil { return nil, err } return convertOldConfigToNew(state.Config), nil } else { 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 { 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 }