func (c *containers) isUpdatable(n string) error {
	if _, ok := c.currentState[n]; !ok {
		return fmt.Errorf("can't update non-existing container %q", n)
	}
	if _, ok := c.desiredState[n]; !ok {
		return fmt.Errorf("can't update container %q, which is scheduler for removal", n)
	}
	return nil
}
isUpdatable determines if given container can be updated.
package container
import (
	"fmt"
	"reflect"
	"github.com/google/go-cmp/cmp"
	"sigs.k8s.io/yaml"
	"github.com/flexkube/libflexkube/internal/util"
	"github.com/flexkube/libflexkube/pkg/container/types"
)
type ContainersInterface interface {
	CheckCurrentState() error
	Deploy() error
	StateToYaml() ([]byte, error)
	ToExported() *Containers
	DesiredState() ContainersState
}
type Containers struct {
	PreviousState ContainersState `json:"previousState,omitempty"`
	DesiredState ContainersState `json:"desiredState,omitempty"`
}
type containers struct {
	previousState containersState
	currentState containersState
	desiredState containersState
}
func (c *Containers) New() (ContainersInterface, error) {
	if err := c.Validate(); err != nil {
		return nil, fmt.Errorf("validating containers configuration: %w", err)
	}
	previousState, _ := c.PreviousState.New()  
	desiredState, _ := c.DesiredState.New()    
	return &containers{
		previousState: previousState.(containersState),
		desiredState:  desiredState.(containersState),
	}, nil
}
func (c *Containers) Validate() error {
	var errors util.ValidateErrors
	if c == nil {
		errors = append(errors, fmt.Errorf("containers must be defined"))
		return errors.Return()
	}
	if (c.PreviousState == nil && c.DesiredState == nil) || (len(c.PreviousState) == 0 && len(c.DesiredState) == 0) {
		errors = append(errors, fmt.Errorf("either current state or desired state must be defined"))
	}
	if _, err := c.PreviousState.New(); err != nil {
		errors = append(errors, fmt.Errorf("validating previous state failed: %w", err))
	}
	if _, err := c.DesiredState.New(); err != nil {
		errors = append(errors, fmt.Errorf("validating desired state failed: %w", err))
	}
	return errors.Return()
}
func (c *Containers) CheckCurrentState() error {
	containers, err := c.New()
	if err != nil {
		return fmt.Errorf("creating containers configuration: %w", err)
	}
	if err := containers.CheckCurrentState(); err != nil {
		return fmt.Errorf("checking current state of the containers: %w", err)
	}
	*c = *containers.ToExported()
	return nil
}
func (c *Containers) Deploy() error {
	containers, err := c.New()
	if err != nil {
		return fmt.Errorf("initializing containers: %w", err)
	}
	if err := containers.CheckCurrentState(); err != nil {
		return fmt.Errorf("checking current state: %w", err)
	}
	if err := containers.Deploy(); err != nil {
		return fmt.Errorf("deploying: %w", err)
	}
	*c = *containers.ToExported()
	return nil
}
func (c *containers) CheckCurrentState() error {
	if c.currentState == nil {
		c.currentState = c.previousState
	}
	return c.currentState.CheckState()
}
func filesToUpdate(d hostConfiguredContainer, c *hostConfiguredContainer) []string {
	if c == nil {
		return util.KeysStringMap(d.configFiles)
	}
	files := []string{}
	for p, content := range d.configFiles {
		if currentContent, exists := c.configFiles[p]; !exists || content != currentContent {
			fmt.Printf("Detected configuration drift for file %q\n", p)
			fmt.Printf("  current: \n%+v\n", currentContent)
			fmt.Printf("  desired: \n%+v\n", content)
			files = append(files, p)
		}
	}
	return files
}
func (c *containers) ensureConfigured(n string) error {
	d := c.desiredState[n]
	if d == nil {
		return nil
	}
	r := c.currentState[n]
	f := filesToUpdate(*d, r)
	err := d.Configure(f)
	if err != nil && reflect.DeepEqual(f, filesToUpdate(*d, r)) {
		return fmt.Errorf("no files has been updated: %w", err)
	}
	if r == nil {
		c.currentState[n] = d
		r = d
	}
	r.configFiles = d.configFiles
	if err != nil {
		return fmt.Errorf("updating configuration: %w", err)
	}
	return nil
}
func ensureRunning(c *hostConfiguredContainer) error {
	if c == nil {
		return fmt.Errorf("can't start non-existing container")
	}
	if c.container.Status().Running() {
		return nil
	}
	return c.Start()
}
func (c *containers) ensureExists(n string) error {
	r := c.currentState[n]
	if r != nil && r.container.Status().Exists() {
		return nil
	}
	fmt.Printf("Creating new container %q\n", n)
	d := c.desiredState[n]
	err := c.desiredState.CreateAndStart(n)
	if err != nil && !d.container.Status().Exists() {  
		return fmt.Errorf("creating container: %w", err)
	}
	if r == nil {
		c.currentState[n] = d
		r = d
	}
	*r.container.Status() = *d.container.Status()
	if err != nil {
		return fmt.Errorf("starting container: %w", err)
	}
	return nil
}