From 481552c02bbf041e7bd55c9d84284bf365851bcd Mon Sep 17 00:00:00 2001 From: Vishnu Kannan Date: Tue, 24 Jun 2014 21:34:09 +0000 Subject: [PATCH] Created a global runtime checkpoint for libcontainer. Got rid of the network specific runtime checkpoint. Docker-DCO-1.1-Signed-off-by: Vishnu Kannan (github: vishh) --- api/api.go => api.go | 8 ++--- checkpoint.go | 65 ++++++++++++++++++++++++++++++++++++++++ namespaces/exec.go | 7 +++++ network/checkpoint.go | 58 +++++++---------------------------- network/stats.go | 6 ++-- network/veth.go | 7 +++-- nsinit/stats.go | 10 +++---- nsinit/utils.go | 12 -------- api/types.go => types.go | 2 +- 9 files changed, 98 insertions(+), 77 deletions(-) rename api/api.go => api.go (66%) create mode 100644 checkpoint.go rename api/types.go => types.go (94%) diff --git a/api/api.go b/api.go similarity index 66% rename from api/api.go rename to api.go index 54819db77..481c9a56c 100644 --- a/api/api.go +++ b/api.go @@ -1,21 +1,19 @@ -package api +package libcontainer import ( - "github.com/docker/libcontainer" "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/network" ) // Returns all available stats for the given container. -func GetContainerStats(container *libcontainer.Container, networkInfo *network.NetworkRuntimeInfo) (*ContainerStats, error) { +func GetContainerStats(container *Config, runtimeCkpt *RuntimeCkpt) (*ContainerStats, error) { containerStats := NewContainerStats() stats, err := fs.GetStats(container.Cgroups) if err != nil { return containerStats, err } containerStats.CgroupStats = stats - networkStats, err := network.GetStats(networkInfo) + networkStats, err := network.GetStats(&runtimeCkpt.NetworkCkpt) if err != nil { return containerStats, err } diff --git a/checkpoint.go b/checkpoint.go new file mode 100644 index 000000000..9baae65f8 --- /dev/null +++ b/checkpoint.go @@ -0,0 +1,65 @@ +package libcontainer + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/docker/libcontainer/network" +) + +// A checkpoint struct that will contain all runtime checkpointed information. +type RuntimeCkpt struct { + NetworkCkpt network.NetworkCkpt `json:"network_ckpt,omitempty"` +} + +// The name of the network checkpoint file +const runtimeCkptFile = "runtimeCkpt.json" + +var ErrRuntimeCkptNotFound = errors.New("Runtime Checkpoint not found") + +// Returns the path to the network checkpoint given the path to the base directory of network checkpoint. +func getRuntimeCkptPath(basePath string) string { + return filepath.Join(basePath, runtimeCkptFile) +} + +// Updates the Runtime Checkpoint with current checkpoint information from all the subsystems. +func UpdateRuntimeCkpt(basePath string) error { + runtimeCkpt := &RuntimeCkpt{ + NetworkCkpt: *network.NetworkCkptImpl.GetNetworkCkpt(), + } + data, err := json.Marshal(runtimeCkpt) + if err != nil { + return fmt.Errorf("Failed to checkpoint runtime information - %s", err) + } + return ioutil.WriteFile(getRuntimeCkptPath(basePath), data, 0655) +} + +// Loads and returns the rutime checkpointing existing inside basePath. Returns ErrRuntimeCkptNotFound +// if the runtime checkpoint does not exist. +func GetRuntimeCkpt(basePath string) (*RuntimeCkpt, error) { + runtimeCkpt := &RuntimeCkpt{} + checkpointPath := getRuntimeCkptPath(basePath) + f, err := os.Open(checkpointPath) + if err != nil { + if os.IsNotExist(err) { + return runtimeCkpt, ErrRuntimeCkptNotFound + } + return runtimeCkpt, err + } + defer f.Close() + + if err := json.NewDecoder(f).Decode(runtimeCkpt); err != nil { + return runtimeCkpt, err + } + + return runtimeCkpt, nil +} + +// Deletes the runtime checkpoint under basePath +func DeleteNetworkRuntimeInfo(basePath string) error { + return os.Remove(getRuntimeCkptPath(basePath)) +} diff --git a/namespaces/exec.go b/namespaces/exec.go index f89ad4186..4e5d2677e 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -87,6 +87,13 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string return -1, err } + // Update the runtime checkpoint. + if err = libcontainer.UpdateRuntimeCkpt(dataPath); err != nil { + command.Process.Kill() + command.Wait() + return -1, err + } + // Sync with child syncPipe.Close() diff --git a/network/checkpoint.go b/network/checkpoint.go index 0d12b438c..f9f9c3a14 100644 --- a/network/checkpoint.go +++ b/network/checkpoint.go @@ -1,63 +1,25 @@ package network -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" -) - // Struct describing the network specific checkpoint that will be maintained by libcontainer for all running containers // This is an internal checkpoint, so do not depend on it outside of libcontainer. -type NetworkRuntimeInfo struct { +type NetworkCkpt struct { // The name of the veth interface on the Host. VethHost string `json:"veth_host,omitempty"` // The name of the veth interface created inside the container for the child. VethChild string `json:"veth_child,omitempty"` } -// The name of the network checkpoint file -const networkInfoFile = "network.json" +type NetworkCkptIntImpl struct{} -var ErrNetworkRuntimeInfoNotFound = errors.New("Network Checkpoint not found") +var ( + networkCkptInfo = &NetworkCkpt{} + NetworkCkptImpl = &NetworkCkptIntImpl{} +) -// Returns the path to the network checkpoint given the path to the base directory of network checkpoint. -func getNetworkRuntimeInfoPath(basePath string) string { - return filepath.Join(basePath, networkInfoFile) +func (NetworkCkptIntImpl) GetNetworkCkpt() *NetworkCkpt { + return networkCkptInfo } -// Marshalls the input network runtime info struct into a json object and stores it inside basepath. -func writeNetworkRuntimeInfo(networkInfo *NetworkRuntimeInfo, basePath string) error { - data, err := json.Marshal(networkInfo) - if err != nil { - return fmt.Errorf("Failed to checkpoint network runtime information - %s", err) - } - return ioutil.WriteFile(getNetworkRuntimeInfoPath(basePath), data, 0655) -} - -// Loads the network runtime info from the checkpoint and returns the unmarshaled content. -func LoadNetworkRuntimeInfo(basePath string) (NetworkRuntimeInfo, error) { - var networkRuntimeInfo NetworkRuntimeInfo - checkpointPath := getNetworkRuntimeInfoPath(basePath) - f, err := os.Open(checkpointPath) - if err != nil { - if os.IsNotExist(err) { - return networkRuntimeInfo, ErrNetworkRuntimeInfoNotFound - } - return networkRuntimeInfo, err - } - defer f.Close() - - if err := json.NewDecoder(f).Decode(&networkRuntimeInfo); err != nil { - return networkRuntimeInfo, err - } - - return networkRuntimeInfo, nil -} - -// Deletes the network checkpoint under basePath -func deleteNetworkRuntimeInfo(basePath string) error { - return os.Remove(getNetworkRuntimeInfoPath(basePath)) +func (NetworkCkptIntImpl) updateNetworkCkpt(n *NetworkCkpt) { + networkCkptInfo = n } diff --git a/network/stats.go b/network/stats.go index c3afdea43..3481100f8 100644 --- a/network/stats.go +++ b/network/stats.go @@ -20,12 +20,12 @@ type NetworkStats struct { } // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. -func GetStats(networkRuntimeInfo *NetworkRuntimeInfo) (NetworkStats, error) { +func GetStats(networkCkpt *NetworkCkpt) (NetworkStats, error) { // This can happen if the network runtime information is missing - possible if the container was created by an old version of libcontainer. - if networkRuntimeInfo.VethHost == "" { + if networkCkpt.VethHost == "" { return NetworkStats{}, nil } - data, err := readSysfsNetworkStats(networkRuntimeInfo.VethHost) + data, err := readSysfsNetworkStats(networkCkpt.VethHost) if err != nil { return NetworkStats{}, err } diff --git a/network/veth.go b/network/veth.go index c119e0a26..94b0d3ceb 100644 --- a/network/veth.go +++ b/network/veth.go @@ -45,8 +45,11 @@ func (v *Veth) Create(n *Network, nspid int, context map[string]string, dataPath if err := SetInterfaceInNamespacePid(name2, nspid); err != nil { return err } - networkRuntimeInfo := NetworkRuntimeInfo{VethHost: name1, VethChild: name2} - return writeNetworkRuntimeInfo(&networkRuntimeInfo, dataPath) + networkCkpt := NetworkCkptImpl.GetNetworkCkpt() + networkCkpt.VethHost = name1 + networkCkpt.VethChild = name2 + NetworkCkptImpl.updateNetworkCkpt(networkCkpt) + return nil } func (v *Veth) Initialize(config *Network, context map[string]string) error { diff --git a/nsinit/stats.go b/nsinit/stats.go index 3aa860fba..6554cb116 100644 --- a/nsinit/stats.go +++ b/nsinit/stats.go @@ -7,8 +7,6 @@ import ( "github.com/codegangsta/cli" "github.com/docker/libcontainer" - "github.com/docker/libcontainer/api" - "github.com/docker/libcontainer/network" ) var statsCommand = cli.Command{ @@ -23,12 +21,12 @@ func statsAction(context *cli.Context) { log.Fatal(err) } - networkRuntimeInfo, err := loadNetworkRuntimeInfo() + runtimeCkpt, err := libcontainer.GetRuntimeCkpt(dataPath) if err != nil { log.Fatal(err) } - stats, err := getContainerStats(container, &networkRuntimeInfo) + stats, err := getContainerStats(container, runtimeCkpt) if err != nil { log.Fatalf("Failed to get stats - %v\n", err) } @@ -37,8 +35,8 @@ func statsAction(context *cli.Context) { } // returns the container stats in json format. -func getContainerStats(container *libcontainer.Config, networkRuntimeInfo *network.NetworkRuntimeInfo) (string, error) { - stats, err := libcontainer.GetContainerStats(container, networkRuntimeInfo) +func getContainerStats(container *libcontainer.Config, runtimeCkpt *libcontainer.RuntimeCkpt) (string, error) { + stats, err := libcontainer.GetContainerStats(container, runtimeCkpt) if err != nil { return "", err } diff --git a/nsinit/utils.go b/nsinit/utils.go index 703172c1e..44194d885 100644 --- a/nsinit/utils.go +++ b/nsinit/utils.go @@ -7,7 +7,6 @@ import ( "path/filepath" "github.com/docker/libcontainer" - "github.com/docker/libcontainer/network" ) func loadContainer() (*libcontainer.Config, error) { @@ -25,17 +24,6 @@ func loadContainer() (*libcontainer.Config, error) { return container, nil } -func loadNetworkRuntimeInfo() (network.NetworkRuntimeInfo, error) { - data, err := network.LoadNetworkRuntimeInfo(dataPath) - if err != nil { - if err == network.ErrNetworkRuntimeInfoNotFound { - return network.NetworkRuntimeInfo{}, nil - } - return network.NetworkRuntimeInfo{}, err - } - return data, nil -} - func openLog(name string) error { f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755) if err != nil { diff --git a/api/types.go b/types.go similarity index 94% rename from api/types.go rename to types.go index 927de88f7..80dbc2259 100644 --- a/api/types.go +++ b/types.go @@ -1,4 +1,4 @@ -package api +package libcontainer import ( "github.com/docker/libcontainer/cgroups"