Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/kpod/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func runCmd(c *cli.Context) error {
}

logrus.Debug("new container created ", ctr.ID())
if err := ctr.Create(); err != nil {
if err := ctr.Init(); err != nil {
return err
}
logrus.Debug("container storage created for %q", ctr.ID())
Expand Down
141 changes: 61 additions & 80 deletions libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,17 @@ type containerConfig struct {
Spec *spec.Spec `json:"spec"`
ID string `json:"id"`
Name string `json:"name"`
// RootfsFromImage indicates whether the container uses a root
// filesystem from an image, or from a user-provided directory
RootfsFromImage bool
// Directory used as a root filesystem if not configured with an image
RootfsDir string `json:"rootfsDir,omitempty"`
// Information on the image used for the root filesystem
RootfsImageID string `json:"rootfsImageID,omitempty"`
RootfsImageName string `json:"rootfsImageName,omitempty"`
MountLabel string `json:"MountLabel,omitempty"`
UseImageConfig bool `json:"useImageConfig"`
// Whether to keep container STDIN open
Stdin bool
// SELinux mount label for root filesystem
MountLabel string `json:"MountLabel,omitempty"`
// Static directory for container content that will persist across
// reboot
StaticDir string `json:"staticDir"`
// Whether to keep container STDIN open
Stdin bool
// Pod the container belongs to
Pod string `json:"pod,omitempty"`
// Labels is a set of key-value pairs providing additional information
Expand Down Expand Up @@ -154,10 +150,9 @@ func (c *Container) State() (ContainerState, error) {
c.lock.Lock()
defer c.lock.Unlock()

// TODO uncomment when working
// if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
// return ContainerStateUnknown, err
// }
if err := c.runtime.state.UpdateContainer(c); err != nil {
return ContainerStateUnknown, errors.Wrapf(err, "error updating container %s state", c.ID())
}

return c.state.State, nil
}
Expand Down Expand Up @@ -207,18 +202,6 @@ func (c *Container) setupStorage() error {
return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Configured state to have storage set up", c.ID())
}

// If we're configured to use a directory, perform that setup
if !c.config.RootfsFromImage {
// TODO implement directory-based root filesystems
return ErrNotImplemented
}

// Not using a directory, so call into containers/storage
return c.setupImageRootfs()
}

// Set up an image as root filesystem using containers/storage
func (c *Container) setupImageRootfs() error {
// Need both an image ID and image name, plus a bool telling us whether to use the image configuration
if c.config.RootfsImageID == "" || c.config.RootfsImageName == "" {
return errors.Wrapf(ErrInvalidArg, "must provide image ID and image name to use an image")
Expand Down Expand Up @@ -248,16 +231,6 @@ func (c *Container) teardownStorage() error {
return errors.Wrapf(ErrCtrStateInvalid, "cannot remove storage for container %s as it is running or paused", c.ID())
}

if !c.config.RootfsFromImage {
// TODO implement directory-based root filesystems
return ErrNotImplemented
}

return c.teardownImageRootfs()
}

// Completely remove image-based root filesystem for a container
func (c *Container) teardownImageRootfs() error {
if c.state.Mounted {
if err := c.runtime.storageService.StopContainer(c.ID()); err != nil {
return errors.Wrapf(err, "error unmounting container %s root filesystem", c.ID())
Expand All @@ -273,11 +246,15 @@ func (c *Container) teardownImageRootfs() error {
return nil
}

// Create creates a container in the OCI runtime
func (c *Container) Create() (err error) {
// Init creates a container in the OCI runtime
func (c *Container) Init() (err error) {
c.lock.Lock()
defer c.lock.Unlock()

if err := c.runtime.state.UpdateContainer(c); err != nil {
return errors.Wrapf(err, "error updating container %s state", c.ID())
}

if !c.valid {
return errors.Wrapf(ErrCtrRemoved, "container %s is not valid", c.ID())
}
Expand All @@ -286,33 +263,25 @@ func (c *Container) Create() (err error) {
return errors.Wrapf(ErrCtrExists, "container %s has already been created in runtime", c.ID())
}

// If using containers/storage, mount the container
if !c.config.RootfsFromImage {
// TODO implement directory-based root filesystems
if !c.state.Mounted {
return ErrNotImplemented
}
} else {
mountPoint, err := c.runtime.storageService.StartContainer(c.ID())
if err != nil {
return errors.Wrapf(err, "error mounting storage for container %s", c.ID())
}
c.state.Mounted = true
c.state.Mountpoint = mountPoint

logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
mountPoint, err := c.runtime.storageService.StartContainer(c.ID())
if err != nil {
return errors.Wrapf(err, "error mounting storage for container %s", c.ID())
}
c.state.Mounted = true
c.state.Mountpoint = mountPoint

defer func() {
if err != nil {
if err2 := c.runtime.storageService.StopContainer(c.ID()); err2 != nil {
logrus.Errorf("Error unmounting storage for container %s: %v", c.ID(), err2)
}
logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)

c.state.Mounted = false
c.state.Mountpoint = ""
defer func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I belive you need to pass in err

defer func() err error

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary - the error returned by Create() is named err, so this will always be the error returned by the function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.

if err != nil {
if err2 := c.runtime.storageService.StopContainer(c.ID()); err2 != nil {
logrus.Errorf("Error unmounting storage for container %s: %v", c.ID(), err2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logrus.Wrapf

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is such a function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this.

func (c *Container) Create() (err error) {

But you already have it, so all set.

}
}()
}

c.state.Mounted = false
c.state.Mountpoint = ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cleanup - it ensures the state knows the container is unmounted

}
}()

// Make the OCI runtime spec we will use
c.runningSpec = new(spec.Spec)
Expand Down Expand Up @@ -342,9 +311,12 @@ func (c *Container) Create() (err error) {

logrus.Debugf("Created container %s in runc", c.ID())

// TODO should flush this state to disk here
c.state.State = ContainerStateCreated

if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}

return nil
}

Expand All @@ -353,6 +325,10 @@ func (c *Container) Start() error {
c.lock.Lock()
defer c.lock.Unlock()

if err := c.runtime.state.UpdateContainer(c); err != nil {
return errors.Wrapf(err, "error updating container %s state", c.ID())
}

if !c.valid {
return ErrCtrRemoved
}
Expand All @@ -368,10 +344,13 @@ func (c *Container) Start() error {

logrus.Debugf("Started container %s", c.ID())

// TODO should flush state to disk here
c.state.StartedTime = time.Now()
c.state.State = ContainerStateRunning

if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}

return nil
}

Expand All @@ -394,6 +373,25 @@ func (c *Container) Exec(cmd []string, tty bool, stdin bool) (string, error) {
// Attach attaches to a container
// Returns fully qualified URL of streaming server for the container
func (c *Container) Attach(noStdin bool, keys string, attached chan<- bool) error {
if err := c.runtime.state.UpdateContainer(c); err != nil {
return errors.Wrapf(err, "error updating container %s state", c.ID())
}

if !c.valid {
return errors.Wrapf(ErrCtrRemoved, "container %s is not valid", c.ID())
}

if c.state.State == ContainerStateRunning || c.state.State == ContainerStatePaused {
return errors.Wrapf(ErrCtrStateInvalid, "cannot remove storage for container %s as it is running or paused", c.ID())
}

// TODO is it valid to attach to a frozen container?
if c.state.State == ContainerStateUnknown ||
c.state.State == ContainerStateConfigured ||
c.state.State == ContainerStatePaused {
return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created, running, or stopped containers")
}

// Check the validity of the provided keys first
var err error
detachKeys := []byte{}
Expand All @@ -403,25 +401,12 @@ func (c *Container) Attach(noStdin bool, keys string, attached chan<- bool) erro
return errors.Wrapf(err, "invalid detach keys")
}
}
cStatus := c.state.State

if !(cStatus == ContainerStateRunning || cStatus == ContainerStateCreated) {
return errors.Errorf("%s is not created or running", c.Name())
}
resize := make(chan remotecommand.TerminalSize)
defer close(resize)
err = c.attachContainerSocket(resize, noStdin, detachKeys, attached)

err = c.attachContainerSocket(resize, noStdin, detachKeys, attached)
return err

// TODO
// Re-enable this when mheon is done wth it
//if err != nil {
// return err
//}
//c.ContainerStateToDisk(c)

//return err
}

// Mount mounts a container's filesystem on the host
Expand All @@ -448,10 +433,6 @@ func (c *Container) Export(path string) error {

// Commit commits the changes between a container and its image, creating a new
// image
// If the container was not created from an image (for example,
// WithRootFSFromPath will create a container from a directory on the system),
// a new base image will be created from the contents of the container's
// filesystem
func (c *Container) Commit() (*storage.Image, error) {
return nil, ErrNotImplemented
}
4 changes: 4 additions & 0 deletions libpod/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ var (
// further operations can be performed on it
ErrPodRemoved = errors.New("pod has already been removed")

// ErrDBClosed indicates that the connection to the state database has
// already been closed
ErrDBClosed = errors.New("database connection already closed")

// ErrNotImplemented indicates that the requested functionality is not
// yet present
ErrNotImplemented = errors.New("not yet implemented")
Expand Down
21 changes: 21 additions & 0 deletions libpod/in_memory_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ func NewInMemoryState() (State, error) {
return state, nil
}

// Close the state before shutdown
// This is a no-op as we have no backing disk
func (s *InMemoryState) Close() error {
return nil
}

// Container retrieves a container from its full ID
func (s *InMemoryState) Container(id string) (*Container, error) {
if id == "" {
Expand Down Expand Up @@ -147,6 +153,21 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
return nil
}

// UpdateContainer updates a container's state
// As all state is in-memory, no update will be required
// As such this is a no-op
func (s *InMemoryState) UpdateContainer(ctr *Container) error {
return nil
}

// SaveContainer saves a container's state
// As all state is in-memory, any changes are always reflected as soon as they
// are made
// As such this is a no-op
func (s *InMemoryState) SaveContainer(ctr *Container) error {
return nil
}

// AllContainers retrieves all containers from the state
func (s *InMemoryState) AllContainers() ([]*Container, error) {
ctrs := make([]*Container, 0, len(s.containers))
Expand Down
36 changes: 15 additions & 21 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ func WithSignaturePolicy(path string) RuntimeOption {
}
}

// WithInMemoryState specifies that the runtime will be backed by an in-memory
// state only, and state will not persist after the runtime is shut down
func WithInMemoryState() RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return ErrRuntimeFinalized
}

rt.config.InMemoryState = true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove line.

return nil
}
}

// WithOCIRuntime specifies an OCI runtime to use for running containers
func WithOCIRuntime(runtimePath string) RuntimeOption {
return func(rt *Runtime) error {
Expand Down Expand Up @@ -236,25 +250,6 @@ func WithNoPivotRoot(noPivot bool) RuntimeOption {

// Container Creation Options

// WithRootFSFromPath uses the given path as a container's root filesystem
// No further setup is performed on this path
func WithRootFSFromPath(path string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}

if ctr.config.RootfsDir != "" || ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" {
return errors.Wrapf(ErrInvalidArg, "container already configured with root filesystem")
}

ctr.config.RootfsDir = path
ctr.config.RootfsFromImage = false

return nil
}
}

// WithSELinuxMountLabel sets the mount label for SELinux
func WithSELinuxMountLabel(mountLabel string) CtrCreateOption {
return func(ctr *Container) error {
Expand All @@ -277,14 +272,13 @@ func WithRootFSFromImage(imageID string, imageName string, useImageConfig bool)
return ErrCtrFinalized
}

if ctr.config.RootfsDir != "" || ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" {
if ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" {
return errors.Wrapf(ErrInvalidArg, "container already configured with root filesystem")
}

ctr.config.RootfsImageID = imageID
ctr.config.RootfsImageName = imageName
ctr.config.UseImageConfig = useImageConfig
ctr.config.RootfsFromImage = true

return nil
}
Expand Down
Loading