Skip to content

Commit

Permalink
Created a global runtime checkpoint for libcontainer. Got rid of the …
Browse files Browse the repository at this point in the history
…network specific runtime checkpoint.

Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)
  • Loading branch information
vishh committed Jun 25, 2014
1 parent 9253412 commit 481552c
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 77 deletions.
8 changes: 3 additions & 5 deletions api/api.go → api.go
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
65 changes: 65 additions & 0 deletions checkpoint.go
Original file line number Diff line number Diff line change
@@ -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))
}
7 changes: 7 additions & 0 deletions namespaces/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
58 changes: 10 additions & 48 deletions network/checkpoint.go
Original file line number Diff line number Diff line change
@@ -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"

var ErrNetworkRuntimeInfoNotFound = errors.New("Network Checkpoint not found")

// 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)
}
type NetworkCkptIntImpl struct{}

// 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
}
var (
networkCkptInfo = &NetworkCkpt{}
NetworkCkptImpl = &NetworkCkptIntImpl{}
)

return networkRuntimeInfo, nil
func (NetworkCkptIntImpl) GetNetworkCkpt() *NetworkCkpt {
return networkCkptInfo
}

// Deletes the network checkpoint under basePath
func deleteNetworkRuntimeInfo(basePath string) error {
return os.Remove(getNetworkRuntimeInfoPath(basePath))
func (NetworkCkptIntImpl) updateNetworkCkpt(n *NetworkCkpt) {
networkCkptInfo = n
}
6 changes: 3 additions & 3 deletions network/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
7 changes: 5 additions & 2 deletions network/veth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 4 additions & 6 deletions nsinit/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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)
}
Expand All @@ -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
}
Expand Down
12 changes: 0 additions & 12 deletions nsinit/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"path/filepath"

"github.com/docker/libcontainer"
"github.com/docker/libcontainer/network"
)

func loadContainer() (*libcontainer.Config, error) {
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion api/types.go → types.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package api
package libcontainer

import (
"github.com/docker/libcontainer/cgroups"
Expand Down

0 comments on commit 481552c

Please sign in to comment.