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
27 changes: 27 additions & 0 deletions cmd/aem/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (c *CLI) instanceCmd() *cobra.Command {
cmd.AddCommand(c.instanceAwaitCmd())
cmd.AddCommand(c.instanceBackupCmd())
cmd.AddCommand(c.instanceImportCmd())
cmd.AddCommand(c.instanceUpgradeCmd())
return cmd
}

Expand Down Expand Up @@ -142,6 +143,32 @@ func (c *CLI) instanceCreateCmd() *cobra.Command {
}
}

func (c *CLI) instanceUpgradeCmd() *cobra.Command {
return &cobra.Command{
Use: "upgrade",
Short: "Upgrades AEM instance(s) if needed",
Aliases: []string{"update"},
Run: func(cmd *cobra.Command, args []string) {
localInstances, err := c.aem.InstanceManager().SomeLocals()
if err != nil {
c.Error(err)
return
}
upgradedInstances, err := c.aem.InstanceManager().Upgrade(localInstances)
if err != nil {
c.Error(err)
return
}
c.SetOutput("upgraded", upgradedInstances)
if len(upgradedInstances) > 0 {
c.Changed(fmt.Sprintf("upgraded instance(s) (%d)", len(upgradedInstances)))
} else {
c.Ok("no instance(s) to upgrade")
}
},
}
}

func (c *CLI) instanceStartCmd() *cobra.Command {
return &cobra.Command{
Use: "start",
Expand Down
1 change: 1 addition & 0 deletions pkg/instance_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func (im *InstanceManager) newFromConfig(id string) *Instance {
i.local.SecretVars = cv.GetStringSlice(fmt.Sprintf("instance.config.%s.secret_vars", id))
i.local.SlingProps = cv.GetStringSlice(fmt.Sprintf("instance.config.%s.sling_props", id))
i.local.UnpackDir = cv.GetString(fmt.Sprintf("instance.config.%s.unpack_dir", id))
i.local.AllowInPlaceUpgrade = cv.GetBool(fmt.Sprintf("instance.config.%s.allow_in_place_upgrade", id))
}
return i
}
Expand Down
132 changes: 91 additions & 41 deletions pkg/local_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ import (
type LocalInstance struct {
instance *Instance

Version string
JvmOpts []string
StartOpts []string
RunModes []string
EnvVars []string
SecretVars []string
SlingProps []string
UnpackDir string
Version string
JvmOpts []string
StartOpts []string
RunModes []string
EnvVars []string
SecretVars []string
SlingProps []string
UnpackDir string
AllowInPlaceUpgrade bool
}

type LocalInstanceState struct {
Expand All @@ -50,15 +51,16 @@ type LocalInstanceState struct {
}

const (
LocalInstanceScriptStart = "start"
LocalInstanceScriptStop = "stop"
LocalInstanceScriptStatus = "status"
LocalInstanceBackupExtension = "aemb.tar.zst"
LocalInstanceUser = "admin"
LocalInstanceWorkDirName = common.AppId
LocalInstanceNameCommon = "common"
LocalInstanceSecretsDir = "conf/secret"
LocalInstanceVersionDefault = "1"
LocalInstanceScriptStart = "start"
LocalInstanceScriptStop = "stop"
LocalInstanceScriptStatus = "status"
LocalInstanceBackupExtension = "aemb.tar.zst"
LocalInstanceUser = "admin"
LocalInstanceWorkDirName = common.AppId
LocalInstanceNameCommon = "common"
LocalInstanceSecretsDir = "conf/secret"
LocalInstanceVersionDefault = "1"
LocalInstanceAllowInPlaceUpgradeDefault = false
)

func (li LocalInstance) Instance() *Instance {
Expand All @@ -74,6 +76,7 @@ func NewLocal(i *Instance) *LocalInstance {
li.EnvVars = []string{}
li.SecretVars = []string{}
li.SlingProps = []string{}
li.AllowInPlaceUpgrade = LocalInstanceAllowInPlaceUpgradeDefault
return li
}

Expand Down Expand Up @@ -185,18 +188,21 @@ var (
LocalInstancePasswordRegex = regexp.MustCompile("^[a-zA-Z0-9_]{5,}$")
)

func (li LocalInstance) CheckRecreationNeeded() error {
func (li LocalInstance) CheckUpgradeNeeded() (bool, error) {
createLock := li.createLock()
if createLock.IsLocked() {
state, err := createLock.State()
if err != nil {
return err
return false, err
}
if !state.UpToDate {
return fmt.Errorf("%s > outdated and need to be recreated as distribution JAR changed from '%s' to '%s'", li.instance.IDColor(), state.Locked.JarName, state.Current.JarName)
if li.AllowInPlaceUpgrade {
return true, nil
}
return true, fmt.Errorf("%s > outdated and need to be upgraded as distribution JAR changed from '%s' to '%s'", li.instance.IDColor(), state.Locked.JarName, state.Current.JarName)
}
}
return nil
return false, nil
}

func (li LocalInstance) CheckPassword() error {
Expand Down Expand Up @@ -241,6 +247,21 @@ func (li LocalInstance) Create() error {
return nil
}

func (li LocalInstance) Upgrade() error {
log.Infof("%s > upgrading", li.instance.IDColor())
if err := li.unpackJarFile(); err != nil {
return err
}
if err := li.copyLicenseFile(); err != nil {
return err
}
if err := li.adapt(); err != nil {
return err
}
log.Infof("%s > upgraded", li.instance.IDColor())
return nil
}

func (li LocalInstance) Import() error {
log.Infof("%s > importing", li.instance.IDColor())

Expand Down Expand Up @@ -294,6 +315,33 @@ func (li LocalInstance) unpackJarFile() error {
if !pathx.Exists(startScript) {
return fmt.Errorf("%s > unpacking files went wrong as e.g start script does not exist '%s'", li.instance.IDColor(), startScript)
}

// Only check crx-quickstart/app for JARs
appDir := filepath.Join(li.QuickstartDir(), "app")
jarFiles, err := filepath.Glob(filepath.Join(appDir, "*.jar"))
if err != nil {
return fmt.Errorf("%s > error searching for JAR files in app dir: %w", li.instance.IDColor(), err)
}
if len(jarFiles) > 1 {
type jarInfo struct {
path string
modTime time.Time
}
var jars []jarInfo
for _, path := range jarFiles {
info, err := os.Stat(path)
if err == nil {
jars = append(jars, jarInfo{path, info.ModTime()})
}
}
sort.Slice(jars, func(i, j int) bool {
return jars[i].modTime.After(jars[j].modTime)
})
for _, ji := range jars[1:] {
log.Infof("%s > removing outdated JAR from app dir: %s", li.instance.IDColor(), ji.path)
_ = os.Remove(ji.path)
}
}
return nil
}

Expand Down Expand Up @@ -538,31 +586,33 @@ func (li LocalInstance) updateLock() osx.Lock[localInstanceUpdateLock] {
return zero, err
}
return localInstanceUpdateLock{
Version: li.Version,
HTTPPort: li.instance.HTTP().Port(),
RunModes: strings.Join(li.RunModes, ","),
JVMOpts: strings.Join(li.JvmOpts, " "),
JavaHome: javaHomeDir,
Password: cryptox.HashString(li.instance.password),
EnvVars: strings.Join(li.EnvVars, ","),
SecretVars: cryptox.HashString(strings.Join(li.SecretVars, ",")),
SlingProps: strings.Join(li.SlingProps, ","),
Overrides: overrides,
Version: li.Version,
HTTPPort: li.instance.HTTP().Port(),
RunModes: strings.Join(li.RunModes, ","),
JVMOpts: strings.Join(li.JvmOpts, " "),
JavaHome: javaHomeDir,
Password: cryptox.HashString(li.instance.password),
EnvVars: strings.Join(li.EnvVars, ","),
SecretVars: cryptox.HashString(strings.Join(li.SecretVars, ",")),
SlingProps: strings.Join(li.SlingProps, ","),
Overrides: overrides,
AllowInPlaceUpgrade: li.AllowInPlaceUpgrade,
}, nil
})
}

type localInstanceUpdateLock struct {
Version string `yaml:"version"`
JVMOpts string `yaml:"jvm_opts"`
JavaHome string `yaml:"java_home"`
RunModes string `yaml:"run_modes"`
HTTPPort string `yaml:"http_port"`
Password string `yaml:"password"`
Overrides string `yaml:"overrides"`
EnvVars string `yaml:"env_vars"`
SecretVars string `yaml:"secret_vars"`
SlingProps string `yaml:"sling_props"`
Version string `yaml:"version"`
JVMOpts string `yaml:"jvm_opts"`
JavaHome string `yaml:"java_home"`
RunModes string `yaml:"run_modes"`
HTTPPort string `yaml:"http_port"`
Password string `yaml:"password"`
Overrides string `yaml:"overrides"`
EnvVars string `yaml:"env_vars"`
SecretVars string `yaml:"secret_vars"`
SlingProps string `yaml:"sling_props"`
AllowInPlaceUpgrade bool `yaml:"allow_in_place_upgrade"`
}

func (li LocalInstance) Stop() error {
Expand Down
26 changes: 25 additions & 1 deletion pkg/local_instance_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (o *LocalOpts) Initialize() error {
}
// post-validation phase
for _, instance := range o.manager.Locals() {
if err := instance.Local().CheckRecreationNeeded(); err != nil { // depends on SDK prepare
if _, err := instance.Local().CheckUpgradeNeeded(); err != nil { // depends on SDK prepare
return err
}
}
Expand Down Expand Up @@ -129,6 +129,10 @@ func (im *InstanceManager) CreateAll() ([]Instance, error) {
return im.Create(im.Locals())
}

func (im *InstanceManager) UpgradeAll() ([]Instance, error) {
return im.Upgrade(im.Locals())
}

func (im *InstanceManager) Create(instances []Instance) ([]Instance, error) {
created := []Instance{}
if err := im.LocalOpts.Initialize(); err != nil {
Expand All @@ -147,6 +151,26 @@ func (im *InstanceManager) Create(instances []Instance) ([]Instance, error) {
return created, nil
}

func (im *InstanceManager) Upgrade(instances []Instance) ([]Instance, error) {
upgraded := []Instance{}
if err := im.LocalOpts.Initialize(); err != nil {
return upgraded, err
}
log.Info(InstancesMsg(instances, "upgrading"))
for _, i := range instances {
if !i.local.IsCreated() {
return nil, fmt.Errorf("instance not yet created: %s", i.IDColor())
} else if upgradeNeeded, _ := i.local.CheckUpgradeNeeded(); upgradeNeeded {
err := i.local.Upgrade()
if err != nil {
return nil, err
}
upgraded = append(upgraded, i)
}
}
return upgraded, nil
}

func (im *InstanceManager) Import(instances []Instance) ([]Instance, error) {
imported := []Instance{}
log.Info(InstancesMsg(instances, "importing"))
Expand Down
Loading