Huge amount of linting

Linting
This commit is contained in:
Joel Elkins 2022-08-17 02:24:48 -05:00
parent 9c27d0e6f5
commit b91eb62c34
No known key found for this signature in database
GPG Key ID: 133589DC38921AE2
14 changed files with 214 additions and 102 deletions

View File

@ -38,7 +38,7 @@ var createCmd = &cobra.Command{
names or categories. Multiple arguments are supported.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.CreateCommands() }, 0)
execForEach(conts, func(c *container.Container) command.Set { return c.CreateCommands() }, 0)
},
}

View File

@ -34,12 +34,12 @@ import (
"golang.org/x/exp/slices"
)
func execForEach(tgts []container.Container, getSet func(*container.Container) command.CommandSet, groupScale int) {
func execForEach(tgts []*container.Container, getSet func(*container.Container) command.Set, groupScale int) {
runLevel := make(map[int][]*container.Container)
for i := range tgts {
rl := tgts[i].StartGroup * groupScale
runLevel[rl] = append(runLevel[rl], &tgts[i])
runLevel[rl] = append(runLevel[rl], tgts[i])
}
rls := maps.Keys(runLevel)
@ -58,8 +58,10 @@ func execForEach(tgts []container.Container, getSet func(*container.Container) c
wg := new(sync.WaitGroup)
for i := range cs {
wg.Add(1)
go func(cont *container.Container, set command.CommandSet) {
cont := cs[i]
go func() {
defer wg.Done()
set := getSet(cont)
for _, cmd := range set.Commands {
if err := cmd.Execute(output, fake, set.ID); err != nil {
cont.LogEntry().WithFields(log.Fields{
@ -69,7 +71,7 @@ func execForEach(tgts []container.Container, getSet func(*container.Container) c
return
}
}
}(cs[i], getSet(cs[i]))
}()
}
wg.Wait()
if r != 0 {

View File

@ -39,7 +39,7 @@ affected: the old image will still remain, though untagged, and any defined cont
will still use it.`,
Run: func(cmd *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.PullCommands() }, 0)
execForEach(conts, func(c *container.Container) command.Set { return c.PullCommands() }, 0)
},
}

View File

@ -38,9 +38,9 @@ var recreateCmd = &cobra.Command{
one or more container names or categories. If empty, "all" is assumed.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.RecreateCommands() }, 0)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.ConditionalStartCommands() }, 1)
execForEach(conts, func(c *container.Container) command.Set { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.Set { return c.RecreateCommands() }, 0)
execForEach(conts, func(c *container.Container) command.Set { return c.ConditionalStartCommands() }, 1)
},
}

View File

@ -38,8 +38,8 @@ var restartCmd = &cobra.Command{
one or more container names or categories. If empty, "all" is assumed.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StartCommands() }, 1)
execForEach(conts, func(c *container.Container) command.Set { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.Set { return c.StartCommands() }, 1)
},
}

View File

@ -39,8 +39,8 @@ var rmCmd = &cobra.Command{
If running, they will first be stopped.`,
Run: func(cmd *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.RemoveCommands() }, 0)
execForEach(conts, func(c *container.Container) command.Set { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.Set { return c.RemoveCommands() }, 0)
},
}

View File

@ -38,7 +38,7 @@ import (
var rootCmd = &cobra.Command{
Use: "ccl",
Short: "Manage a set of pre-configured of podman containers",
Version: Version,
Version: version,
Long: `ccl is a utility to manage a set of podman containers. Use with various subcommands
to define, start, stop, or update the container images. Configuration is read
from a toml configuration file, and the utility uses this information to
@ -52,9 +52,9 @@ execute the necessary podman commands.`,
requireConn := []string{"create", "pull", "recreate", "restart", "rm", "start", "stop", "update"}
if slices.Contains(requireConn, cmd.Name()) {
// connect to podman
ConnectMust()
connectMust()
} else {
if err := Connect(); err != nil {
if err := connect(); err != nil {
log.WithField("error", err).Warnln("Connection failed")
}
}
@ -84,14 +84,15 @@ func Execute() {
}
}
func Connect() error {
func connect() error {
var err error
conn, err = bindings.NewConnection(context.WithValue(context.Background(), "output", output), socket)
key := struct{ string }{"output"}
conn, err = bindings.NewConnection(context.WithValue(context.Background(), key, output), socket)
return err
}
func ConnectMust() {
if err := Connect(); err != nil {
func connectMust() {
if err := connect(); err != nil {
log.WithField("error", err).Errorf("Could not connect")
os.Exit(1)
}
@ -105,7 +106,7 @@ func init() {
output = io.Discard
}
})
rootCmd.PersistentFlags().StringVarP(&config.ConfigFile, "config", "c", config.CONFIG_FILE_DEFAULT, "pathname of config file")
rootCmd.PersistentFlags().StringVarP(&config.ConfigFile, "config", "c", config.ConfigFileDefault, "pathname of config file")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "show additional info from command execution")
rootCmd.PersistentFlags().BoolVarP(&fake, "no-action", "n", false, "do not actually execute commands")
rootCmd.PersistentFlags().BoolVarP(&incDisabled, "include-disabled", "a", false, "include category=. containers in actions")

View File

@ -38,7 +38,7 @@ var startCmd = &cobra.Command{
one or more container names or categories. If empty, "all" is assumed.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StartCommands() }, 1)
execForEach(conts, func(c *container.Container) command.Set { return c.StartCommands() }, 1)
},
}

View File

@ -38,7 +38,7 @@ var stopCmd = &cobra.Command{
one or more container names or categories. If empty, "all" is assumed.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.StopCommands() }, -1)
execForEach(conts, func(c *container.Container) command.Set { return c.StopCommands() }, -1)
},
}

View File

@ -38,8 +38,8 @@ var updateCmd = &cobra.Command{
one or more container names or categories. If empty, "all" is assumed.`,
Run: func(_ *cobra.Command, args []string) {
conts := config.Union(args, contMask)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.UpdateCommands() }, -1)
execForEach(conts, func(c *container.Container) command.CommandSet { return c.ConditionalStartCommands() }, 1)
execForEach(conts, func(c *container.Container) command.Set { return c.UpdateCommands() }, -1)
execForEach(conts, func(c *container.Container) command.Set { return c.ConditionalStartCommands() }, 1)
},
}

View File

@ -35,14 +35,14 @@ var versionCmd = &cobra.Command{
Short: "Show version info",
Long: `Output the ccl binary's version`,
Run: func(cmd *cobra.Command, _ []string) {
fmt.Println("ccl version", Version)
fmt.Println("ccl version", version)
},
}
var (
//go:embed version.txt
version string
Version string = strings.TrimSpace(version)
rawVersion string
version = strings.TrimSpace(rawVersion)
)
func init() {

View File

@ -1,4 +1,7 @@
/*
Package command is used to manage the container management instructions required to carry out
tasks desired by the user, such as "create"
Copyright © 2022 Joel D. Elkins <joel@elkins.co>
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -27,46 +30,64 @@ import (
"os/exec"
)
type CommandType int
// Type is one of the Ct... constants, indicating the underlying method
// for executing a command.
type cType int
// Types of commands:
// - CtNop: No operation; an empty placeholder
// - CtShell: A shell command -- string to be fed to /bin/sh -c
// - CtFunc: A go function of type `func() error`
// - CtIndirect: A reference to another command. When executed, the underlying command is executed.
// - CtSet: An ordered list of commands
// - CtDebug: A debug message is printed upon execution, but does no other action
// - CtConditional: A function and two commands are provided. When evaluated,
// the function, having signature `func() bool`, is executed. If the result is
// true, then the first command is executed, and if false the second one.
const (
CT_NOP CommandType = iota
CT_SHELL
CT_FUNC
CT_INDIRECT
CT_SET
CT_DEBUG
CT_CONDITIONAL
ctNop cType = iota
ctShell
ctFunc
ctIndirect
ctSet
ctDebug
ctConditional
)
func (ct CommandType) String() string {
func (ct cType) String() string {
switch ct {
case CT_NOP:
case ctNop:
return "NOP"
case CT_SHELL:
case ctShell:
return "SHELL"
case CT_FUNC:
case ctFunc:
return "FUNC"
case CT_INDIRECT:
case ctIndirect:
return "INDIRECT"
case CT_SET:
case ctSet:
return "SET"
case CT_DEBUG:
case ctDebug:
return "DEBUG"
case CT_CONDITIONAL:
case ctConditional:
return "CONDITIONAL"
default:
return "UNKOWN"
}
}
// Command combines a Type with an `interface{}`, representing a task (or a set
// of tasks, in the case of CtSet) to be executed. Create a Command with one of
// the `NewXxxCommand` functions.
type Command struct {
Type CommandType
Type cType
Command interface{}
}
// Commands reflects an ordered grouping of `Command`s
type Commands []Command
type CommandSet struct{
// Set bundes a `Commands` object with an arbitrary ID for verbose output
type Set struct {
ID string
Commands
}
@ -83,32 +104,46 @@ type conditional struct {
ElseCmd Command
}
// NewShell creates a new shell-type command from a string. Upon execution, the
// string will be fed to `/bin/sh -c`
func NewShell(cmd string) Command {
return Command{CT_SHELL, cmd}
return Command{ctShell, cmd}
}
// NewFunc creates a command consisting of go function of type `func() error`
func NewFunc(name string, f func() error) Command {
return Command{CT_FUNC, errFunc{name, f}}
return Command{ctFunc, errFunc{name, f}}
}
// NewIndirect creates a reference to another command. When executed, the underlying
// command is executed.
func NewIndirect(c Command) Command {
return Command{CT_INDIRECT, c}
return Command{ctIndirect, c}
}
func NewSet(cs CommandSet) Command {
return Command{CT_SET, cs.Commands}
// NewSet creates a single command containing an ordered list of commands. These
// commands will be executed in order with this set-type command is executed.
func NewSet(cs Set) Command {
return Command{ctSet, cs.Commands}
}
// NewDebug returns a command that prints a debug message upon execution, but
// does no other action
func NewDebug(msg string) Command {
return Command{CT_DEBUG, msg}
return Command{ctDebug, msg}
}
// NewNop returns a placeholder command. When executed, nothing is done other
// than to note that it was encountered in the output.
func NewNop() Command {
return Command{CT_NOP, nil}
return Command{ctNop, nil}
}
// NewConditional takes a function and two commands as arguments. When evaluated,
// the function, having signature `func() bool`, is executed. If the result is
// true, then the first command is executed, and if false the second one.
func NewConditional(name string, ifPart func() bool, thenPart Command, elsePart Command) Command {
return Command{CT_CONDITIONAL, conditional{
return Command{ctConditional, conditional{
Name: name,
Condition: ifPart,
ThenCmd: thenPart,
@ -116,7 +151,9 @@ func NewConditional(name string, ifPart func() bool, thenPart Command, elsePart
}}
}
func (cmds CommandSet) Execute(output io.Writer, fake bool) error {
// Execute the Set with the privileges of the user running the process.
// Warning: in the case of a shell command, this could do anything.
func (cmds Set) Execute(output io.Writer, fake bool) error {
for _, c := range cmds.Commands {
if err := c.Execute(output, fake, cmds.ID); err != nil {
return err
@ -125,11 +162,13 @@ func (cmds CommandSet) Execute(output io.Writer, fake bool) error {
return nil
}
// Execute the Command with the privileges of the user running the process.
// Warning: in the case of a shell command, this could do anything.
func (c Command) Execute(output io.Writer, fake bool, commandSetID string) error {
switch c.Type {
case CT_NOP:
case ctNop:
fmt.Fprintf(output, "%s: %s\n", commandSetID, c.Type)
case CT_SHELL:
case ctShell:
cmd := c.Command.(string)
fmt.Fprintf(output, "%s: %s sh -c \"%s\"\n", commandSetID, c.Type, cmd)
if !fake {
@ -137,7 +176,7 @@ func (c Command) Execute(output io.Writer, fake bool, commandSetID string) error
fmt.Fprint(output, string(out))
return err
}
case CT_FUNC:
case ctFunc:
ef := c.Command.(errFunc)
fmt.Fprintf(output, "%s: %s %s\n", commandSetID, c.Type, ef.Name)
if !fake {
@ -146,10 +185,10 @@ func (c Command) Execute(output io.Writer, fake bool, commandSetID string) error
}
return nil
}
case CT_INDIRECT:
case ctIndirect:
ct := c.Command.(Command)
return ct.Execute(output, fake, commandSetID)
case CT_SET:
case ctSet:
cs := c.Command.(Commands)
for i := range cs {
err := cs[i].Execute(output, fake, commandSetID)
@ -157,7 +196,7 @@ func (c Command) Execute(output io.Writer, fake bool, commandSetID string) error
return err
}
}
case CT_CONDITIONAL:
case ctConditional:
cond := c.Command.(conditional)
if fake {
// in a fake setting, we don't know which branch will be followed,
@ -173,11 +212,10 @@ func (c Command) Execute(output io.Writer, fake bool, commandSetID string) error
fmt.Fprintf(output, "%s: %s %s: %v\n", commandSetID, c.Type, cond.Name, branch)
if branch {
return cond.ThenCmd.Execute(output, fake, commandSetID)
} else {
}
return cond.ElseCmd.Execute(output, fake, commandSetID)
}
}
case CT_DEBUG:
case ctDebug:
msg := c.Command.(string)
fmt.Fprintf(output, "%s: %s %s\n", commandSetID, c.Type, msg)
}

View File

@ -1,3 +1,27 @@
/*
Package config is used manage initialize and house the main program data
structures, as well as marshalling the configuration to and from toml.
Copyright © 2022 Joel D. Elkins <joel@elkins.co>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package config
import (
@ -18,15 +42,17 @@ import (
)
const (
CONFIG_FILE_DEFAULT = "/etc/ccl.toml"
ConfigFileDefault = "/etc/ccl.toml" // ConfigFileDefault is default configuration file path
)
var (
ConfigFile = CONFIG_FILE_DEFAULT
Networks = []network.Network{}
Containers = []container.Container{}
ConfigFile = ConfigFileDefault // ConfigFile is the path to the configuration file to use in a particular invocation.
Networks = []*network.Network{} // Networks is the program-global set of congiured network.Networks structures
Containers = []*container.Container{} // Containers is the program-global set of configured container.Container structures.
)
// Categories returns a slice of all of the distinct categories found in the
// configured containers.
func Categories() []string {
categories := []string{"all"}
gs := hashset.New()
@ -40,7 +66,12 @@ func Categories() []string {
return categories
}
func Union(ids []string, catMask []string) (conts []container.Container) {
// Union - given a list of identifiers ("all", a category, or a container
// name), as well as a category mask, will yieLd a list of configured
// containers that match the identifiers but not the mask. As envisioned, the
// default mask would be ".", i.e., the tool would normally exclude containers
// "disabled" by setting their category to a singLe period (".")
func Union(ids []string, catMask []string) (conts []*container.Container) {
if len(ids) == 0 {
ids = []string{"all"}
}
@ -60,7 +91,7 @@ func Union(ids []string, catMask []string) (conts []container.Container) {
}
for _, c := range h.Values() {
name := c.(string)
match := slices.IndexFunc(Containers, func(c container.Container) bool { return c.Name == name })
match := slices.IndexFunc(Containers, func(c *container.Container) bool { return c.Name == name })
conts = append(conts, Containers[match])
}
if len(conts) == 0 {
@ -69,7 +100,7 @@ func Union(ids []string, catMask []string) (conts []container.Container) {
"catMask": catMask,
}).Warnln("No matching containers. If disabled, try adding -a")
}
slices.SortFunc(conts, func(a, b container.Container) bool {
slices.SortFunc(conts, func(a, b *container.Container) bool {
if a.Category < b.Category {
return true
}
@ -81,8 +112,9 @@ func Union(ids []string, catMask []string) (conts []container.Container) {
return
}
func UnionNetworks(ids []string) []network.Network {
nets := make([]network.Network, len(Networks))
// UnionNetworks is like Union but for Networks, and also no mask.
func UnionNetworks(ids []string) []*network.Network {
nets := make([]*network.Network, len(Networks))
rejects := []int{}
copy(nets, Networks)
for i := range nets {
@ -101,11 +133,14 @@ func UnionNetworks(ids []string) []network.Network {
return nets
}
// Init will parse the configuration file, create and populate the in-memory
// data structures. Will call container.Init() on each container created in
// this way.
func Init(conn context.Context) error {
// A parsing convenience
type parse struct {
Networks []network.Network
Containers []container.Container
Networks []*network.Network
Containers []*container.Container
}
f, err := os.ReadFile(ConfigFile)
@ -121,22 +156,29 @@ func Init(conn context.Context) error {
for i := range Containers {
Containers[i].Init(conn, Networks)
}
slices.SortFunc(Containers, func(a, b container.Container) bool {
slices.SortFunc(Containers, func(a, b *container.Container) bool {
return a.Name < b.Name
})
return nil
}
// Show will output a toml configuration of the provided identifiers ("all",
// category, or container name). The resulting string would presumably be sent
// to the terminal or a file.
//
// Other than ordering of fields and possible inclusion of some fields with
// their default values, the generated toml should be completely compatible
// with the actual configuration. Dogfood safe.
func Show(ids []string, contMask []string) string {
type parse struct {
Containers []container.Container `toml:"containers,omitempty"`
Networks []network.Network `toml:"networks,omitempty"`
Containers []*container.Container `toml:"containers,omitempty"`
Networks []*network.Network `toml:"networks,omitempty"`
}
getNet := func(name string) *network.Network {
for i := range Networks {
if Networks[i].Name == name {
return &Networks[i]
return Networks[i]
}
}
return nil

View File

@ -1,4 +1,7 @@
/*
Package container encapuslates both the metadata structure and main
operations to be presented to the user in the `cmd` module.
Copyright © 2022 Joel D. Elkins <joel@elkins.co>
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -19,7 +22,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package container
import (
@ -41,6 +43,9 @@ import (
"gopkg.in/guregu/null.v4"
)
// Container houses the metadata that may be specified by this utility when
// creating a container. A couple of fields (Name and Image) are mandatory to
// specify, but the rest will use the libpod or otherwise sensible defaults.
type Container struct {
Category string `toml:"category"`
Name string `toml:"name"`
@ -54,9 +59,9 @@ type Container struct {
Restart string `toml:"restart,omitempty"`
Umask null.Int `toml:"umask,omitempty"`
User string `toml:"user,omitempty"`
ExposeTcp []uint16 `toml:"expose_tcp,omitempty"`
ExposeUdp []uint16 `toml:"expose_udp,omitempty"`
PortsTcp map[uint16]uint16 `toml:"ports,omitempty"`
ExposeTCP []uint16 `toml:"expose_tcp,omitempty"`
ExposeUDP []uint16 `toml:"expose_udp,omitempty"`
PortsTCP map[uint16]uint16 `toml:"ports,omitempty"`
NetNS string `toml:"netns,omitempty"`
StartGroup int `toml:"group,omitempty"`
@ -66,13 +71,15 @@ type Container struct {
wasRunning bool
}
func (c *Container) Init(conn context.Context, nets []network.Network) error {
// Init will initialize a new container structure by filling in network details
// and by querying other metadata from libpod, if possible.
func (c *Container) Init(conn context.Context, nets []*network.Network) error {
// initialize user-provided definitions
for i := range c.Networks {
var n *network.Network
for j := range nets {
if nets[j].Name == c.Networks[i].Name {
n = &nets[j]
n = nets[j]
}
}
if n == nil {
@ -115,6 +122,9 @@ func (c *Container) Init(conn context.Context, nets []network.Network) error {
return err
}
// LogEntry will return a *logrus.LogEntry, with some basic fields populated
// for this container. The idea is that the calling code would add other fields
// (optionally) and do something with the error.
func (c *Container) LogEntry() *log.Entry {
f := log.Fields{
"container": c.Name,
@ -134,14 +144,16 @@ func (c *Container) pull() error {
return err
}
func (c *Container) newCommandSet(op string, cmds cmd.Commands) cmd.CommandSet {
return cmd.CommandSet{
func (c *Container) newCommandSet(op string, cmds cmd.Commands) cmd.Set {
return cmd.Set{
ID: fmt.Sprintf("%s-%s", op, c.Name),
Commands: cmds,
}
}
func (c *Container) PullCommands() cmd.CommandSet {
// PullCommands will return a cmd.Set to pull the specified image using the
// libpod API
func (c *Container) PullCommands() cmd.Set {
return c.newCommandSet("PULL", cmd.Commands{
cmd.NewFunc("do_pull", func() error {
return c.pull()
@ -149,7 +161,9 @@ func (c *Container) PullCommands() cmd.CommandSet {
})
}
func (c *Container) CreateCommands() cmd.CommandSet {
// CreateCommands returns a cmd.Set that will create a container from the
// configured metadata. The container should not exist.
func (c *Container) CreateCommands() cmd.Set {
if c.Image == "" {
return c.newCommandSet("CREATE", cmd.Commands{
cmd.NewFunc("image_error", func() error {
@ -179,15 +193,15 @@ func (c *Container) CreateCommands() cmd.CommandSet {
}
expose := map[uint16]string{}
for _, p := range c.ExposeTcp {
for _, p := range c.ExposeTCP {
expose[p] = "tcp"
}
for _, p := range c.ExposeUdp {
for _, p := range c.ExposeUDP {
expose[p] = "udp"
}
portMappings := []types.PortMapping{}
for ph, pc := range c.PortsTcp {
for ph, pc := range c.PortsTCP {
portMappings = append(portMappings, types.PortMapping{
HostPort: ph,
ContainerPort: pc,
@ -256,15 +270,17 @@ func (c *Container) CreateCommands() cmd.CommandSet {
})
}
func (c *Container) RecreateCommands() cmd.CommandSet {
// RecreateCommands will stop (if running), remove (if exists), (re)create, and restart (if
// it was initially running) a container. The image is not pulled.
func (c *Container) RecreateCommands() cmd.Set {
return c.newCommandSet("RECREATE", cmd.Commands{
cmd.NewSet(c.RemoveCommands()),
cmd.NewSet(c.CreateCommands()),
})
}
// unexported version just removes the container without attempting a stop.
func (c *Container) RemoveCommands() cmd.CommandSet {
// RemoveCommands removes a container (as if by `podman rm -f`)
func (c *Container) RemoveCommands() cmd.Set {
return c.newCommandSet("remove", cmd.Commands{
cmd.NewFunc("remove_if_exists", func() error {
c.cdataLock.Lock()
@ -281,7 +297,8 @@ func (c *Container) RemoveCommands() cmd.CommandSet {
})
}
func (c *Container) StartCommands() cmd.CommandSet {
// StartCommands will start a container if it's not already running.
func (c *Container) StartCommands() cmd.Set {
return c.newCommandSet("START", cmd.Commands{
cmd.NewFunc("start_container", func() error {
c.cdataLock.Lock()
@ -318,6 +335,8 @@ func (c *Container) StartCommands() cmd.CommandSet {
})
}
// IsRunning returns true if libpod reports the container status is running, or
// false otherwise. If an error happens, the default value is false.
func (c *Container) IsRunning() bool {
if c.cdata != nil && c.cdata.State != nil {
return c.cdata.State.Running
@ -325,6 +344,7 @@ func (c *Container) IsRunning() bool {
return false
}
// IsCreated tests whether libpod sees the container as being created (running or not)
func (c *Container) IsCreated() bool {
if c.cdata == nil || c.cdata.ID == "" {
return false
@ -332,7 +352,9 @@ func (c *Container) IsCreated() bool {
return true
}
func (c *Container) UpdateCommands() cmd.CommandSet {
// UpdateCommands will pull the image (to force updates) and then recreate the
// container. It will be stopped first.
func (c *Container) UpdateCommands() cmd.Set {
return c.newCommandSet("UPDATE", cmd.Commands{
cmd.NewSet(c.PullCommands()),
cmd.NewSet(c.StopCommands()),
@ -341,7 +363,10 @@ func (c *Container) UpdateCommands() cmd.CommandSet {
})
}
func (c *Container) ConditionalStartCommands() cmd.CommandSet {
// ConditionalStartCommands - several of the other command sets would leave the
// container in the stopped state. This set will restart a container if it was
// running when this container was first initialized.
func (c *Container) ConditionalStartCommands() cmd.Set {
if c.wasRunning {
return c.StartCommands()
}
@ -350,7 +375,9 @@ func (c *Container) ConditionalStartCommands() cmd.CommandSet {
})
}
func (c *Container) StopCommands() cmd.CommandSet {
// StopCommands will stop a container if it is running, defining a 10 second
// timeout before the processes are killed by lippod
func (c *Container) StopCommands() cmd.Set {
return c.newCommandSet("STOP", cmd.Commands{
cmd.NewFunc("stop_if_running", func() error {
c.cdataLock.Lock()
@ -385,6 +412,8 @@ func (c *Container) populateCData() error {
return err
}
// Pid will return the host process id of the main container process (pid
// 1 inside the container)
func (c *Container) Pid() int {
if c.cdata != nil && c.cdata.State != nil {
return c.cdata.State.Pid
@ -394,7 +423,7 @@ func (c *Container) Pid() int {
func (c *Container) assureNetNS() error {
if nil == c.cdata || nil == c.cdata.NetworkSettings {
return fmt.Errorf("Network namespace not available!")
return fmt.Errorf("network namespace not available")
}
netns := c.cdata.NetworkSettings.SandboxKey
if err := exec.Command("rm", "-f", "/var/run/netns/"+c.Name).Run(); err != nil {