Skip to content

Commit

Permalink
apply: Add --upgrade option
Browse files Browse the repository at this point in the history
The executor implement now a simply logic
to upgrade an existing project.
When the --upgrade option is used the
existing node are replaced sequentially
and are executed the hooks pre-node-upgrade
and post-node-upgrade.
  • Loading branch information
geaaru committed Jan 19, 2024
1 parent ac4a5c5 commit 633b030
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 60 deletions.
3 changes: 3 additions & 0 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func newApplyCommand(config *specs.LxdComposeConfig) *cobra.Command {

skipSync, _ := cmd.Flags().GetBool("skip-sync")
destroy, _ := cmd.Flags().GetBool("destroy")
upgrade, _ := cmd.Flags().GetBool("upgrade")
prefix, _ := cmd.Flags().GetString("nodes-prefix")

composer.SetFlagsDisabled(disabledFlags)
Expand All @@ -83,6 +84,7 @@ func newApplyCommand(config *specs.LxdComposeConfig) *cobra.Command {
composer.SetGroupsEnabled(enabledGroups)
composer.SetSkipSync(skipSync)
composer.SetNodesPrefix(prefix)
composer.SetUpgradeMode(upgrade)

projects := args[0:]

Expand Down Expand Up @@ -153,6 +155,7 @@ func newApplyCommand(config *specs.LxdComposeConfig) *cobra.Command {
flags.StringSliceVar(&varsFiles, "vars-file", []string{},
"Add additional environments vars file.")
flags.Bool("skip-sync", false, "Disable sync of files.")
flags.Bool("upgrade", false, "Enable upgrade mode.")
flags.Bool("destroy", false, "Destroy the selected groups at the end.")
flags.String("nodes-prefix", "", "Customize project nodes name with a prefix")

Expand Down
205 changes: 145 additions & 60 deletions pkg/loader/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,87 +423,102 @@ func (i *LxdCInstance) ApplyGroup(group *specs.LxdCGroup, proj *specs.LxdCProjec

if !isPresent {

// Retrieve pre-node-creation hooks
preCreationHooks := i.GetNodeHooks4Event(specs.HookPreNodeCreation, proj, group, &node)
// Run pre-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(preCreationHooks),
specs.HookPreNodeCreation,
node.GetName()))
err = i.ProcessHooks(&preCreationHooks, proj, group, &node)
// Execute the pre-node-creation hooks,
// create the container and run the post-node-creation
// hooks.
err := i.createInstance(
proj, group, &node,
executor,
instanceProfiles,
)
if err != nil {
return err
}

profiles := []string{}
profiles = append(profiles, group.CommonProfiles...)
profiles = append(profiles, node.Profiles...)

configMap := node.GetLxdConfig(group.GetLxdConfig())

i.Logger.Debug(fmt.Sprintf("[%s] Using profiles %s",
node.GetName(), profiles))

i.Logger.Debug(fmt.Sprintf("[%s] Using config map %s",
node.GetName(), configMap))
} else {

err := i.validateProfiles(instanceProfiles, profiles)
isRunning, err := executor.IsRunningContainer(node.GetName())
if err != nil {
i.Logger.Error(
fmt.Sprintf("Error on check if container %s is running: %s",
node.GetName(), err.Error()))
return err
}

err = executor.CreateContainerWithConfig(node.GetName(), node.ImageSource,
node.ImageRemoteServer, profiles, configMap)
if err != nil {
i.Logger.Error("Error on create container " +
node.GetName() + ":" + err.Error())
return err
}
if i.Upgrade {

// POST: The instance is already present
// but the upgrade flag is enable.

if isRunning {

preNodeUpgradeHooks := i.GetNodeHooks4Event(
specs.HookPreNodeUpgrade,
proj, group, &node)

// Run post-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(preNodeUpgradeHooks),
specs.HookPreNodeUpgrade, node.GetName()))
err = i.ProcessHooks(&preNodeUpgradeHooks, proj, group, &node)
if err != nil {
return err
}

}

// Wait ip
if node.Wait4Ip() > 0 {
err = executor.WaitIpOfContainer(node.GetName(), node.Wait4Ip())
// POST: The running container is stopped
// and destroyed.
err = executor.DeleteContainer(node.GetName())
if err != nil {
i.Logger.Error("Something goes wrong on waiting for the ip address: " +
err.Error())
i.Logger.Error("Error on destroy container " + node.GetName() +
": " + err.Error())
return err
}
}

postCreationHooks := i.GetNodeHooks4Event(specs.HookPostNodeCreation, proj, group, &node)
// Execute the pre-node-creation hooks,
// create the container and run the post-node-creation
// hooks.
err := i.createInstance(
proj, group, &node,
executor,
instanceProfiles,
)
if err != nil {
return err
}

// Run post-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(postCreationHooks),
specs.HookPostNodeCreation, node.GetName()))
err = i.ProcessHooks(&postCreationHooks, proj, group, &node)
if err != nil {
return err
}
postNodeUpgradeHooks := i.GetNodeHooks4Event(
specs.HookPostNodeUpgrade,
proj, group, &node)

} else {
isRunning, err := executor.IsRunningContainer(node.GetName())
if err != nil {
i.Logger.Error(
fmt.Sprintf("Error on check if container %s is running: %s",
node.GetName(), err.Error()))
return err
}
if !isRunning {
// Run post-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Node %s is already present but not running. I'm starting it.",
proj.Name, group.Name, node.GetName()))

err = executor.StartContainer(node.GetName())
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(postNodeUpgradeHooks),
specs.HookPostNodeUpgrade, node.GetName()))
err = i.ProcessHooks(&postNodeUpgradeHooks, proj, group, &node)
if err != nil {
i.Logger.Error(
fmt.Sprintf("Error on start container %s: %s",
node.GetName(), err.Error()))
return err
}

} else {

if !isRunning {
// Run post-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Node %s is already present but not running. I'm starting it.",
proj.Name, group.Name, node.GetName()))

err = executor.StartContainer(node.GetName())
if err != nil {
i.Logger.Error(
fmt.Sprintf("Error on start container %s: %s",
node.GetName(), err.Error()))
return err
}
}
}

}
Expand Down Expand Up @@ -608,6 +623,76 @@ func (i *LxdCInstance) ApplyGroup(group *specs.LxdCGroup, proj *specs.LxdCProjec
return err
}

func (i *LxdCInstance) createInstance(
proj *specs.LxdCProject,
group *specs.LxdCGroup,
node *specs.LxdCNode,
executor *lxd_executor.LxdCExecutor,
instanceProfiles []string) error {

// Retrieve pre-node-creation hooks
preCreationHooks := i.GetNodeHooks4Event(specs.HookPreNodeCreation, proj, group, node)
// Run pre-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(preCreationHooks),
specs.HookPreNodeCreation,
node.GetName()))
err := i.ProcessHooks(&preCreationHooks, proj, group, node)
if err != nil {
return err
}

profiles := []string{}
profiles = append(profiles, group.CommonProfiles...)
profiles = append(profiles, node.Profiles...)

configMap := node.GetLxdConfig(group.GetLxdConfig())

i.Logger.Debug(fmt.Sprintf("[%s] Using profiles %s",
node.GetName(), profiles))

i.Logger.Debug(fmt.Sprintf("[%s] Using config map %s",
node.GetName(), configMap))

err = i.validateProfiles(instanceProfiles, profiles)
if err != nil {
return err
}

err = executor.CreateContainerWithConfig(node.GetName(), node.ImageSource,
node.ImageRemoteServer, profiles, configMap)
if err != nil {
i.Logger.Error("Error on create container " +
node.GetName() + ":" + err.Error())
return err
}

// Wait ip
if node.Wait4Ip() > 0 {
err = executor.WaitIpOfContainer(node.GetName(), node.Wait4Ip())
if err != nil {
i.Logger.Error("Something goes wrong on waiting for the ip address: " +
err.Error())
return err
}
}

postCreationHooks := i.GetNodeHooks4Event(specs.HookPostNodeCreation, proj, group, node)

// Run post-node-creation hooks
i.Logger.Debug(fmt.Sprintf(
"[%s - %s] Running %d %s hooks for node %s... ",
proj.Name, group.Name, len(postCreationHooks),
specs.HookPostNodeCreation, node.GetName()))
err = i.ProcessHooks(&postCreationHooks, proj, group, node)
if err != nil {
return err
}

return nil
}

func (i *LxdCInstance) ApplyCommand(c *specs.LxdCCommand, proj *specs.LxdCProject, envs []string, varfiles []string) error {

if c == nil {
Expand Down
5 changes: 5 additions & 0 deletions pkg/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,16 @@ type LxdCInstance struct {
GroupsEnabled []string
GroupsDisabled []string
NodesPrefix string

Upgrade bool
}

func NewLxdCInstance(config *specs.LxdComposeConfig) *LxdCInstance {
ans := &LxdCInstance{
Config: config,
Logger: log.NewLxdCLogger(config),
Environments: make([]specs.LxdCEnvironment, 0),
Upgrade: false,
}

// Initialize logging
Expand All @@ -75,6 +78,8 @@ func (i *LxdCInstance) SetNodesPrefix(s string) { i.NodesPrefix = s }
func (i *LxdCInstance) GetNodesPrefix() string { return i.NodesPrefix }
func (i *LxdCInstance) SetSkipSync(v bool) { i.SkipSync = v }
func (i *LxdCInstance) GetSkipSync() bool { return i.SkipSync }
func (i *LxdCInstance) SetUpgradeMode(v bool) { i.Upgrade = v }
func (i *LxdCInstance) GetUpgradeMode() bool { return i.Upgrade }
func (i *LxdCInstance) GetGroupsEnabled() []string { return i.GroupsEnabled }
func (i *LxdCInstance) GetGroupsDisabled() []string { return i.GroupsDisabled }
func (i *LxdCInstance) SetGroupsEnabled(groups []string) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/specs/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const (
HookPostGroupShutdown = "post-group-shutdown"
HookPreNodeShutdown = "pre-node-shutdown"
HookPostNodeShutdown = "post-node-shutdown"

HookPreNodeUpgrade = "pre-node-upgrade"
HookPostNodeUpgrade = "post-node-upgrade"
)

func getHooks(hooks *[]LxdCHook, event string) []LxdCHook {
Expand Down

0 comments on commit 633b030

Please sign in to comment.