Skip to content
Open
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
Binary file modified bundle/windows/prod/vm-application-manager.zip
Binary file not shown.
91 changes: 91 additions & 0 deletions internal/actionplan/executehelper.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package actionplan

import (
"bufio"
"bytes"
"crypto/md5"
"fmt"
"io"
"os"
"os/signal"
"path"
"path/filepath"
"syscall"
"time"

Expand Down Expand Up @@ -218,6 +220,10 @@ func (actionPlan *ActionPlan) executeHelper(registryHandler packageregistry.IPac
signal.Stop(interruptSignal)
}

if vmAppPackageCurrent.EnableApplicationEvents {
logApplicationEvents(vmAppPackageCurrent.DownloadDir, appName, act.actionToPerform, errorMessageToReturn, eem, actionPlan)
}

if isDeleteOperation {
delete(registry, appName)
// also cleanup directory
Expand Down Expand Up @@ -280,3 +286,88 @@ func verifyMD5CheckSum(filePath string, checkSum []byte) (bool, error) {
}
return bytes.Equal(checkSumNew, checkSum), nil
}

func logApplicationEvents(downloadDir string, appName string, actionPerformed packageregistry.ActionEnum, errorMessageToReturn error, eem *extensionevents.ExtensionEventManager, actionPlan *ActionPlan) () {
//kusto log limit
maxEvents := 30
eventCount := 0
isFirstStdErrEvent := true;
isFirstStdOutEvent := true;
loggingStr := ""

//read std err file to write to kusto
stderrFileName := filepath.Join(downloadDir, "stderr")
stderrFile, err := os.Open(stderrFileName)
if err != nil {
errorMessageToReturn = extensionerrors.CombineErrors(errorMessageToReturn, errors.Wrapf(err, "Error opening std err file for application %s", appName))
} else {
// create reader + buffer
stderrReader := bufio.NewReader(stderrFile)
stderrBuffer := make([]byte, 16*1024) //16 KB buffer due to event size constraint

for eventCount <= maxEvents {
// read content to buffer
bytesRead, err := stderrReader.Read(stderrBuffer)
if err != nil {
if err != io.EOF {
errorMessageToReturn = extensionerrors.CombineErrors(errorMessageToReturn, errors.Wrapf(err, "Error reading std err file for application %s", appName))
} else if isFirstStdErrEvent {
eem.LogErrorEvent(appName, actionPerformed.ToString() + " stderr: ")
}
break
}
if bytesRead != 0 {
loggingStr = string(stderrBuffer[:bytesRead])
}
if eventCount == 0 {
eem.LogErrorEvent(appName, actionPerformed.ToString() + " stderr: " + loggingStr)
} else {
eem.LogErrorEvent(appName, loggingStr)
}
eventCount++;
}
}
defer stderrFile.Close()

//read std out file to write to kusto
stdoutFileName := filepath.Join(downloadDir, "stdout")
stdoutFile, err := os.Open(stdoutFileName)
if err != nil {
errorMessageToReturn = extensionerrors.CombineErrors(errorMessageToReturn, errors.Wrapf(err, "Error opening std out file for application %s", appName))
} else {
// create reader + buffer
stdoutReader := bufio.NewReader(stdoutFile)
stdoutBuffer := make([]byte, 16*1024) //16 KB buffer due to event size constraint

for eventCount <= maxEvents {
// read content to buffer
bytesRead, err := stdoutReader.Read(stdoutBuffer)
if err != nil {
if err != io.EOF {
errorMessageToReturn = extensionerrors.CombineErrors(errorMessageToReturn, errors.Wrapf(err, "Error reading std out file for application %s", appName))
} else if isFirstStdOutEvent {
eem.LogInformationalEvent(appName, actionPerformed.ToString() + " stdout: ")
}
break
}
if bytesRead != 0 {
loggingStr = string(stdoutBuffer[:bytesRead])
}
if isFirstStdOutEvent {
eem.LogInformationalEvent(appName, actionPerformed.ToString() + " stdout: " + loggingStr)
isFirstStdOutEvent = false;
} else {
eem.LogInformationalEvent(appName, loggingStr)
}
eventCount++;
}
}
defer stdoutFile.Close()

//check if max count reached and log summary
if (eventCount == maxEvents) {
actionPlan.logger.Info("Maximum event count %d reached for application %s, view remaining logs in VM.", maxEvents, appName)
} else {
actionPlan.logger.Info("Logged all application events for application %s", appName)
}
}
73 changes: 41 additions & 32 deletions internal/hostgacommunicator/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,60 @@ var (

// VMAppMetadata contains the format of the metadata returned by HostGAPlugin
type VMAppMetadata struct {
ApplicationName string `json:"name"`
Version string `json:"version"`
InstallCommand string `json:"install"`
UpdateCommand string `json:"update"`
RemoveCommand string `json:"remove"`
DirectDownloadOnly bool `json:"directOnly"`
ConfigExists bool
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
RebootBehavior string `json:"scriptBehaviorAfterReboot"`
ApplicationName string `json:"name"`
Version string `json:"version"`
InstallCommand string `json:"install"`
UpdateCommand string `json:"update"`
RemoveCommand string `json:"remove"`
DirectDownloadOnly bool `json:"directOnly"`
ConfigExists bool
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
RebootBehavior string `json:"scriptBehaviorAfterReboot"`
EnableApplicationEvents bool `json:"enableApplicationEvents"`
}

type VMAppMetadataReceiver struct {
ApplicationName string `json:"name"`
Version string `json:"version"`
InstallCommand string `json:"install"`
UpdateCommand string `json:"update"`
RemoveCommand string `json:"remove"`
DirectDownloadOnly string `json:"directOnly"`
Package string `json:"package"`
Config string `json:"config"`
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
RebootBehavior string `json:"scriptBehaviorAfterReboot"`
ApplicationName string `json:"name"`
Version string `json:"version"`
InstallCommand string `json:"install"`
UpdateCommand string `json:"update"`
RemoveCommand string `json:"remove"`
DirectDownloadOnly string `json:"directOnly"`
Package string `json:"package"`
Config string `json:"config"`
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
RebootBehavior string `json:"scriptBehaviorAfterReboot"`
EnableApplicationEvents string `json:"enableApplicationEvents"`
}

func (receiver *VMAppMetadataReceiver) MapToVMAppMetadata() *VMAppMetadata {
func (receiver *VMAppMetadataReceiver) MapToVMAppMetadata() (*VMAppMetadata) {
directDownloadOnly, err := strconv.ParseBool(receiver.DirectDownloadOnly)
if err != nil {
// assume directDownloadOnly is false when parsing fails
directDownloadOnly = false
}

enableApplicationEvents, err := strconv.ParseBool(receiver.EnableApplicationEvents)
if err != nil {
// assume enableApplicationEvents is false when parsing fails
enableApplicationEvents = false
}

configExists := receiver.Config != ""
vmAppMetadata := VMAppMetadata{
ApplicationName: receiver.ApplicationName,
Version: receiver.Version,
InstallCommand: receiver.InstallCommand,
UpdateCommand: receiver.UpdateCommand,
RemoveCommand: receiver.RemoveCommand,
DirectDownloadOnly: directDownloadOnly,
ConfigExists: configExists,
PackageFileName: receiver.PackageFileName,
ConfigFileName: receiver.ConfigFileName,
RebootBehavior: receiver.RebootBehavior,
ApplicationName: receiver.ApplicationName,
Version: receiver.Version,
InstallCommand: receiver.InstallCommand,
UpdateCommand: receiver.UpdateCommand,
RemoveCommand: receiver.RemoveCommand,
DirectDownloadOnly: directDownloadOnly,
ConfigExists: configExists,
PackageFileName: receiver.PackageFileName,
ConfigFileName: receiver.ConfigFileName,
RebootBehavior: receiver.RebootBehavior,
EnableApplicationEvents: enableApplicationEvents,
}
return &vmAppMetadata
}
Expand Down
36 changes: 19 additions & 17 deletions internal/packageregistry/packageregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,24 @@ type DesiredPackageRegistry map[string]*VMAppPackageIncoming
type VMAppPackageCurrentCollection []*VMAppPackageCurrent

type VMAppPackageCurrent struct {
ApplicationName string `json:"applicationName"`
Version string `json:"version"`
InstallCommand string `json:"install"`
RemoveCommand string `json:"remove"`
UpdateCommand string `json:"update"`
DirectDownloadOnly bool `json:"directOnly"`
ConfigExists bool `json:"configExists"`
OngoingOperation ActionEnum `json:"ongoingOperation"`
DownloadDir string `json:"downloadDir"`
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
IsDeleted bool `json:"isDeleted"`
PackageFileMD5Checksum []byte `json:"packageFileMD5Checksum"`
ConfigFileMD5Checksum []byte `json:"configFileMD5Checksum"`
Result string `json:"result"`
RebootBehavior RebootBehaviorEnum `json:"rebootBehavior"`
NumRebootsOccurred int `json:"numRebootsOccurred"`
ApplicationName string `json:"applicationName"`
Version string `json:"version"`
InstallCommand string `json:"install"`
RemoveCommand string `json:"remove"`
UpdateCommand string `json:"update"`
DirectDownloadOnly bool `json:"directOnly"`
ConfigExists bool `json:"configExists"`
OngoingOperation ActionEnum `json:"ongoingOperation"`
DownloadDir string `json:"downloadDir"`
PackageFileName string `json:"packageFileName"`
ConfigFileName string `json:"configFileName"`
IsDeleted bool `json:"isDeleted"`
PackageFileMD5Checksum []byte `json:"packageFileMD5Checksum"`
ConfigFileMD5Checksum []byte `json:"configFileMD5Checksum"`
Result string `json:"result"`
RebootBehavior RebootBehaviorEnum `json:"rebootBehavior"`
NumRebootsOccurred int `json:"numRebootsOccurred"`
EnableApplicationEvents bool `json:"enableApplicationEvents"`
}

func (vmAppPackageCurrent *VMAppPackageCurrent) GetWorkingDirectory(environment *handlerenv.HandlerEnvironment) string {
Expand All @@ -125,6 +126,7 @@ type VMAppPackageIncoming struct {
IsDeleted bool `json:"isDeleted"`
TreatFailureAsDeploymentFailure bool `json:"treatFailureAsDeploymentFailure"`
RebootBehavior RebootBehaviorEnum `json:"rebootBehavior"`
EnableApplicationEvents bool `json:"enableApplicationEvents"`
}

type IPackageRegistry interface {
Expand Down
29 changes: 29 additions & 0 deletions internal/packageregistry/packageregistry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,35 @@ func TestPackageRegistryDeserialization_NumRebootsOccurred_DefaultToZero(t *test
assert.NoError(t, err, "operation should not throw error")
}

func TestPackageRegistryDeserialization_EnableAppEvents_DefaultToFalse(t *testing.T) {
initializeTest(t)
defer cleanupTest()

var pkgHndlr IPackageRegistry
pkgHndlr, err := New(nopLog(), &hndlEnv, time.Second)
assert.NoError(t, err, "operation should not throw error")

// Overwrite package2
pkg := packageRegistry["package2"]
pkg.EnableApplicationEvents = true
packageRegistry["package2"] = pkg

err = pkgHndlr.WriteToDisk(packageRegistry)
assert.NoError(t, err, "operation should not throw error")

result, err := pkgHndlr.GetExistingPackages()
assert.NoError(t, err, "operation should not throw error")

package1 := result["package1"]
package2 := result["package2"]

assert.Equal(t, false, package1.EnableApplicationEvents, "deserializing package from registry without EnableApplicationEvents set should default to false")
assert.Equal(t, true, package2.EnableApplicationEvents, "EnableApplicationEvents for package2 should be true")

err = pkgHndlr.Close()
assert.NoError(t, err, "operation should not throw error")
}

func TestValuesAreProperlySaved(t *testing.T) {
initializeTest(t)
defer cleanupTest()
Expand Down
23 changes: 12 additions & 11 deletions internal/packageregistry/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,18 @@ func VMAppPackageIncomingToVmAppPackageCurrent(incoming *VMAppPackageIncoming) (
}

current = &VMAppPackageCurrent{
ApplicationName: incoming.ApplicationName,
Version: incoming.Version,
InstallCommand: incoming.InstallCommand,
RemoveCommand: incoming.RemoveCommand,
UpdateCommand: incoming.UpdateCommand,
DirectDownloadOnly: incoming.DirectDownloadOnly,
ConfigExists: incoming.ConfigExists,
OngoingOperation: NoAction,
PackageFileName: packageFileName,
ConfigFileName: configFileName,
RebootBehavior: incoming.RebootBehavior,
ApplicationName: incoming.ApplicationName,
Version: incoming.Version,
InstallCommand: incoming.InstallCommand,
RemoveCommand: incoming.RemoveCommand,
UpdateCommand: incoming.UpdateCommand,
DirectDownloadOnly: incoming.DirectDownloadOnly,
ConfigExists: incoming.ConfigExists,
OngoingOperation: NoAction,
PackageFileName: packageFileName,
ConfigFileName: configFileName,
RebootBehavior: incoming.RebootBehavior,
EnableApplicationEvents: incoming.EnableApplicationEvents,
}
return current
}
1 change: 1 addition & 0 deletions main/resolvevmapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func getVMAppIncomingCollection(settings extdeserialization.VmAppProtectedSettin
PackageFileName: vmAppInfo.PackageFileName,
TreatFailureAsDeploymentFailure: app.TreatFailureAsDeploymentFailure,
RebootBehavior: applicationRebootBehavior,
EnableApplicationEvents: vmAppInfo.EnableApplicationEvents,
}
incomingCollection = append(incomingCollection, &incomingPackage)
}
Expand Down