-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Implementation of SQL-backed state #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c6fe443
cb56716
763e372
4bc3acc
57300be
657cb1b
12f19ca
b10fb66
8981384
f2894ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -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 | ||
| } | ||
|
|
@@ -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") | ||
|
|
@@ -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()) | ||
|
|
@@ -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()) | ||
| } | ||
|
|
@@ -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() { | ||
| 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) | ||
|
||
| } | ||
| }() | ||
| } | ||
|
|
||
| c.state.Mounted = false | ||
| c.state.Mountpoint = "" | ||
|
||
| } | ||
| }() | ||
|
|
||
| // Make the OCI runtime spec we will use | ||
| c.runningSpec = new(spec.Spec) | ||
|
|
@@ -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 | ||
| } | ||
|
|
||
|
|
@@ -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 | ||
| } | ||
|
|
@@ -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 | ||
| } | ||
|
|
||
|
|
@@ -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{} | ||
|
|
@@ -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 | ||
|
|
@@ -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 | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
||
|
||
| return nil | ||
| } | ||
| } | ||
|
|
||
| // WithOCIRuntime specifies an OCI runtime to use for running containers | ||
| func WithOCIRuntime(runtimePath string) RuntimeOption { | ||
| return func(rt *Runtime) error { | ||
|
|
@@ -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 { | ||
|
|
@@ -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 | ||
| } | ||
|
|
||
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree.