Implement linux factory and container with readonly interface
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
6bf1e4ddfc
commit
6310a958e6
21
api_temp.go
21
api_temp.go
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
Temporary API endpoint for libcontainer while the full API is finalized (api.go).
|
||||
*/
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer/cgroups/fs"
|
||||
"github.com/docker/libcontainer/network"
|
||||
)
|
||||
|
||||
// TODO(vmarmol): Complete Stats() in final libcontainer API and move users to that.
|
||||
// DEPRECATED: The below portions are only to be used during the transition to the official API.
|
||||
// Returns all available stats for the given container.
|
||||
func GetStats(container *Config, state *State) (stats *ContainerStats, err error) {
|
||||
stats = &ContainerStats{}
|
||||
if stats.CgroupStats, err = fs.GetStats(state.CgroupPaths); err != nil {
|
||||
return stats, err
|
||||
}
|
||||
stats.NetworkStats, err = network.GetStats(&state.NetworkState)
|
||||
return stats, err
|
||||
}
|
24
error.go
24
error.go
|
@ -8,7 +8,6 @@ const (
|
|||
// Factory errors
|
||||
IdInUse ErrorCode = iota
|
||||
InvalidIdFormat
|
||||
// TODO: add Load errors
|
||||
|
||||
// Container errors
|
||||
ContainerDestroyed
|
||||
|
@ -19,14 +18,29 @@ const (
|
|||
SystemError
|
||||
)
|
||||
|
||||
func (c ErrorCode) String() string {
|
||||
switch c {
|
||||
case IdInUse:
|
||||
return "Id already in use"
|
||||
case InvalidIdFormat:
|
||||
return "Invalid format"
|
||||
case ContainerDestroyed:
|
||||
return "Container destroyed"
|
||||
case ContainerPaused:
|
||||
return "Container paused"
|
||||
case ConfigInvalid:
|
||||
return "Invalid configuration"
|
||||
case SystemError:
|
||||
return "System Error"
|
||||
default:
|
||||
return "Unknown error"
|
||||
}
|
||||
}
|
||||
|
||||
// API Error type.
|
||||
type Error interface {
|
||||
error
|
||||
|
||||
// Returns the stack trace, if any, which identifies the
|
||||
// point at which the error occurred.
|
||||
Stack() []byte
|
||||
|
||||
// Returns a verbose string including the error message
|
||||
// and a representation of the stack trace suitable for
|
||||
// printing.
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package libcontainer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
var newLine = []byte("\n")
|
||||
|
||||
func newGenericError(err error, c ErrorCode) Error {
|
||||
return &GenericError{
|
||||
timestamp: time.Now(),
|
||||
err: err,
|
||||
code: c,
|
||||
stack: captureStackTrace(2),
|
||||
}
|
||||
}
|
||||
|
||||
func captureStackTrace(skip int) string {
|
||||
buf := make([]byte, 4096)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
|
||||
lines := bytes.Split(buf, newLine)
|
||||
return string(bytes.Join(lines[skip:], newLine))
|
||||
}
|
||||
|
||||
type GenericError struct {
|
||||
timestamp time.Time
|
||||
code ErrorCode
|
||||
err error
|
||||
stack string
|
||||
}
|
||||
|
||||
func (e *GenericError) Error() string {
|
||||
return fmt.Sprintf("[%d] %s: %s", e.code, e.code, e.err)
|
||||
}
|
||||
|
||||
func (e *GenericError) Code() ErrorCode {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e *GenericError) Detail() string {
|
||||
return fmt.Sprintf("[%d] %s\n%s", e.code, e.err, e.stack)
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// +build linux
|
||||
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer/cgroups/fs"
|
||||
"github.com/docker/libcontainer/cgroups/systemd"
|
||||
"github.com/docker/libcontainer/network"
|
||||
)
|
||||
|
||||
type linuxContainer struct {
|
||||
id string
|
||||
root string
|
||||
config *Config
|
||||
state *State
|
||||
}
|
||||
|
||||
func (c *linuxContainer) ID() string {
|
||||
return c.id
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Config() *Config {
|
||||
return c.config
|
||||
}
|
||||
|
||||
func (c *linuxContainer) RunState() (*RunState, Error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Processes() ([]int, Error) {
|
||||
var (
|
||||
err error
|
||||
pids []int
|
||||
)
|
||||
|
||||
if systemd.UseSystemd() {
|
||||
pids, err = systemd.GetPids(c.config.Cgroups)
|
||||
} else {
|
||||
pids, err = fs.GetPids(c.config.Cgroups)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Stats() (*ContainerStats, Error) {
|
||||
var (
|
||||
err error
|
||||
stats = &ContainerStats{}
|
||||
)
|
||||
|
||||
if systemd.UseSystemd() {
|
||||
stats.CgroupStats, err = systemd.GetStats(c.config.Cgroups)
|
||||
} else {
|
||||
stats.CgroupStats, err = fs.GetStats(c.config.Cgroups)
|
||||
}
|
||||
if err != nil {
|
||||
return stats, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
if stats.NetworkStats, err = network.GetStats(&c.state.NetworkState); err != nil {
|
||||
return stats, newGenericError(err, SystemError)
|
||||
}
|
||||
return stats, nil
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// +build linux
|
||||
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
configFilename = "config.json"
|
||||
stateFilename = "state.json"
|
||||
)
|
||||
|
||||
// New returns a linux based container factory based in the root directory.
|
||||
func New(root string) (Factory, Error) {
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
return &linuxFactory{
|
||||
root: root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// linuxFactory implements the default factory interface for linux based systems.
|
||||
type linuxFactory struct {
|
||||
// root is the root directory
|
||||
root string
|
||||
}
|
||||
|
||||
func (l *linuxFactory) Create(id string, config *Config) (Container, Error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (l *linuxFactory) Load(id string) (ContainerInfo, Error) {
|
||||
containerRoot := filepath.Join(l.root, id)
|
||||
config, err := l.loadContainerConfig(containerRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state, err := l.loadContainerState(containerRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &linuxContainer{
|
||||
id: id,
|
||||
root: containerRoot,
|
||||
config: config,
|
||||
state: state,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *linuxFactory) loadContainerConfig(root string) (*Config, Error) {
|
||||
f, err := os.Open(filepath.Join(root, configFilename))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, newGenericError(err, ContainerDestroyed)
|
||||
}
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var config *Config
|
||||
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
||||
return nil, newGenericError(err, ConfigInvalid)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (l *linuxFactory) loadContainerState(root string) (*State, Error) {
|
||||
f, err := os.Open(filepath.Join(root, stateFilename))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, newGenericError(err, ContainerDestroyed)
|
||||
}
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var state *State
|
||||
if err := json.NewDecoder(f).Decode(&state); err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
return state, nil
|
||||
}
|
|
@ -48,6 +48,7 @@ func main() {
|
|||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "nspid"},
|
||||
cli.StringFlag{Name: "console"},
|
||||
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
|
||||
}
|
||||
|
||||
app.Before = preload
|
||||
|
|
|
@ -16,23 +16,23 @@ var statsCommand = cli.Command{
|
|||
}
|
||||
|
||||
func statsAction(context *cli.Context) {
|
||||
container, err := loadConfig()
|
||||
factory, err := libcontainer.New(context.GlobalString("root"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
state, err := libcontainer.GetState(dataPath)
|
||||
container, err := factory.Load(context.Args().First())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
stats, err := libcontainer.GetStats(container, state)
|
||||
stats, err := container.Stats()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
data, err := json.MarshalIndent(stats, "", "\t")
|
||||
data, jerr := json.MarshalIndent(stats, "", "\t")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal(jerr)
|
||||
}
|
||||
|
||||
fmt.Printf("%s", data)
|
||||
|
|
Loading…
Reference in New Issue