Skip to content

Commit 7da6da1

Browse files
authored
Adds extension events to RCV2 (#58)
* Adds extension events * PR feedback * PR feedback * Fixes build break * Fixes unit tests * Creates events directory for tests * Fixes unit tests
1 parent f14a87f commit 7da6da1

9 files changed

Lines changed: 239 additions & 74 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.24.5
66

77
require (
88
github.com/Azure/azure-extension-foundation v0.0.0-20250620154556-caff9e3c3c5c
9-
github.com/Azure/azure-extension-platform v0.0.0-20240610175536-404c704f82f8
9+
github.com/Azure/azure-extension-platform v0.0.0-20250107200156-aa20f765d49f
1010
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
1111
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
1212
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ github.com/Azure/azure-extension-foundation v0.0.0-20250620154556-caff9e3c3c5c h
22
github.com/Azure/azure-extension-foundation v0.0.0-20250620154556-caff9e3c3c5c/go.mod h1:sNC6lMTUkXwjrQ+nttr6GXhDfvSGT7t3UDq30BEYzu8=
33
github.com/Azure/azure-extension-platform v0.0.0-20240610175536-404c704f82f8 h1:4AgLx0eXWAzh4nL7eBzwxoQaZEk5Hp2Ilq33YwYzEos=
44
github.com/Azure/azure-extension-platform v0.0.0-20240610175536-404c704f82f8/go.mod h1:nEQQIC3RKmMnpdc+RakYHIdu556jdcHv67ML8PdsQeQ=
5+
github.com/Azure/azure-extension-platform v0.0.0-20250107200156-aa20f765d49f h1:ddsUz/suc9txCMz/xWOslqNMvzhbWFMTflUrbcMNoSw=
6+
github.com/Azure/azure-extension-platform v0.0.0-20250107200156-aa20f765d49f/go.mod h1:0458BvQsi5ch6kn+KZtI5m88Z3L9UFXdoY1+6nKdivY=
57
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
68
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
79
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=

internal/cmds/cmds.go

Lines changed: 117 additions & 31 deletions
Large diffs are not rendered by default.

internal/cmds/cmds_test.go

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212
"strings"
1313
"testing"
1414

15+
"github.com/Azure/azure-extension-platform/pkg/extensionevents"
16+
"github.com/Azure/azure-extension-platform/pkg/handlerenv"
17+
"github.com/Azure/azure-extension-platform/pkg/logging"
1518
"github.com/Azure/run-command-handler-linux/internal/constants"
1619
"github.com/Azure/run-command-handler-linux/internal/files"
1720
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
@@ -74,7 +77,15 @@ func Test_CopyMrseqFiles_MrseqFilesAreCopied(t *testing.T) {
7477
os.Create(filepath.Join(previousStatusDirectory, "ABCD.1.status"))
7578
os.Create(filepath.Join(previousStatusDirectory, "abc.cs")) // this should not be copied to currentExtensionVersionDirectory
7679

77-
err = CopyStateForUpdate(log.NewContext(log.NewNopLogger()))
80+
tempDir, _ := os.MkdirTemp("", "deletecmd")
81+
defer os.RemoveAll(tempDir)
82+
handlerEnvironment := handlerenv.HandlerEnvironment{
83+
EventsFolder: tempDir,
84+
}
85+
86+
extensionLogger := logging.New(nil)
87+
extensionEventManager := extensionevents.New(extensionLogger, &handlerEnvironment)
88+
err = CopyStateForUpdate(log.NewContext(log.NewNopLogger()), extensionEventManager)
7889
require.Nil(t, err)
7990

8091
files, _ = ioutil.ReadDir(currentExtensionVersionDirectory)
@@ -178,23 +189,24 @@ func Test_checkAndSaveSeqNum(t *testing.T) {
178189

179190
func Test_update_e2e_cmd(t *testing.T) {
180191
tempDir, _ := os.MkdirTemp("", "deletecmd")
192+
defer os.RemoveAll(tempDir)
193+
181194
DataDir, _ = os.MkdirTemp("", "datadir")
195+
defer os.RemoveAll(DataDir)
196+
182197
oldVersionDirectory := filepath.Join(tempDir, "Microsoft.CPlat.Core.RunCommandHandlerLinux-1.3.8")
183198
newVersionDirectory := filepath.Join(tempDir, "Microsoft.CPlat.Core.RunCommandHandlerLinux-1.3.9")
184199
err := os.Mkdir(oldVersionDirectory, 0755)
185200
require.Nil(t, err, "Could not create old version subdirectory")
186201
err = os.Mkdir(newVersionDirectory, 0755)
187202
require.Nil(t, err, "Could not create new version subdirectory")
188-
oldStatusPath := filepath.Join(oldVersionDirectory, constants.StatusFileDirectory)
189-
err = os.Mkdir(oldStatusPath, 0755)
190-
require.Nil(t, err, "Could not create old version status subdirectory")
191-
newStatusPath := filepath.Join(newVersionDirectory, constants.StatusFileDirectory)
192-
err = os.Mkdir(newStatusPath, 0755)
193-
require.Nil(t, err, "Could not create new version status subdirectory")
203+
oldStatusPath := create_folder(t, oldVersionDirectory, constants.StatusFileDirectory)
204+
newStatusPath := create_folder(t, newVersionDirectory, constants.StatusFileDirectory)
205+
oldEventsPath := create_folder(t, oldVersionDirectory, constants.ExtensionEventsDirectory)
206+
newEventsPath := create_folder(t, newVersionDirectory, constants.ExtensionEventsDirectory)
194207

195208
fakeEnv := types.HandlerEnvironment{}
196-
fakeEnv.HandlerEnvironment.ConfigFolder = oldVersionDirectory
197-
fakeEnv.HandlerEnvironment.StatusFolder = oldStatusPath
209+
update_handler_env(&fakeEnv, oldStatusPath, oldVersionDirectory, oldEventsPath)
198210

199211
// We start on the old version
200212
os.Setenv(constants.ExtensionPathEnvName, oldVersionDirectory)
@@ -213,8 +225,7 @@ func Test_update_e2e_cmd(t *testing.T) {
213225
os.Setenv(constants.ExtensionVersionEnvName, "1.3.9")
214226
os.Setenv(constants.ExtensionPathEnvName, newVersionDirectory)
215227
os.Setenv(constants.ExtensionVersionUpdatingFromEnvName, "1.3.8")
216-
fakeEnv.HandlerEnvironment.StatusFolder = newStatusPath
217-
fakeEnv.HandlerEnvironment.ConfigFolder = newVersionDirectory
228+
update_handler_env(&fakeEnv, newStatusPath, newVersionDirectory, newEventsPath)
218229
update_handler(t, fakeEnv, tempDir)
219230

220231
// Now, WALA will uninstall the old extension
@@ -230,23 +241,24 @@ func Test_update_e2e_cmd(t *testing.T) {
230241

231242
func Test_udpate_e2e_problematic_version(t *testing.T) {
232243
tempDir, _ := os.MkdirTemp("", "deletecmd")
244+
defer os.RemoveAll(tempDir)
245+
233246
DataDir, _ = os.MkdirTemp("", "datadir")
247+
defer os.RemoveAll(DataDir)
248+
234249
oldVersionDirectory := filepath.Join(tempDir, "Microsoft.CPlat.Core.RunCommandHandlerLinux-1.3.17")
235250
newVersionDirectory := filepath.Join(tempDir, "Microsoft.CPlat.Core.RunCommandHandlerLinux-1.3.18")
236251
err := os.Mkdir(oldVersionDirectory, 0755)
237252
require.Nil(t, err, "Could not create old version subdirectory")
238253
err = os.Mkdir(newVersionDirectory, 0755)
239254
require.Nil(t, err, "Could not create new version subdirectory")
240-
oldStatusPath := filepath.Join(oldVersionDirectory, constants.StatusFileDirectory)
241-
err = os.Mkdir(oldStatusPath, 0755)
242-
require.Nil(t, err, "Could not create old version status subdirectory")
243-
newStatusPath := filepath.Join(newVersionDirectory, constants.StatusFileDirectory)
244-
err = os.Mkdir(newStatusPath, 0755)
245-
require.Nil(t, err, "Could not create new version status subdirectory")
255+
oldStatusPath := create_folder(t, oldVersionDirectory, constants.StatusFileDirectory)
256+
newStatusPath := create_folder(t, newVersionDirectory, constants.StatusFileDirectory)
257+
oldEventsPath := create_folder(t, oldVersionDirectory, constants.ExtensionEventsDirectory)
258+
newEventsPath := create_folder(t, newVersionDirectory, constants.ExtensionEventsDirectory)
246259

247260
fakeEnv := types.HandlerEnvironment{}
248-
fakeEnv.HandlerEnvironment.ConfigFolder = oldVersionDirectory
249-
fakeEnv.HandlerEnvironment.StatusFolder = oldStatusPath
261+
update_handler_env(&fakeEnv, oldStatusPath, oldVersionDirectory, oldEventsPath)
250262

251263
// We start on the old version
252264
os.Setenv(constants.ExtensionPathEnvName, oldVersionDirectory)
@@ -280,8 +292,7 @@ func Test_udpate_e2e_problematic_version(t *testing.T) {
280292
os.Setenv(constants.ExtensionVersionEnvName, "1.3.18")
281293
os.Setenv(constants.ExtensionPathEnvName, newVersionDirectory)
282294
os.Setenv(constants.ExtensionVersionUpdatingFromEnvName, "1.3.17")
283-
fakeEnv.HandlerEnvironment.StatusFolder = newStatusPath
284-
fakeEnv.HandlerEnvironment.ConfigFolder = newVersionDirectory
295+
update_handler_env(&fakeEnv, newStatusPath, newVersionDirectory, newEventsPath)
285296
update_handler(t, fakeEnv, tempDir)
286297

287298
// Now, WALA will uninstall the old extension
@@ -301,6 +312,19 @@ func Test_udpate_e2e_problematic_version(t *testing.T) {
301312
enable_extension(t, fakeEnv, newVersionDirectory, "stubbornChipmunk", true, 1)
302313
}
303314

315+
func create_folder(t *testing.T, versionDirectory string, folderName string) string {
316+
folderPath := filepath.Join(versionDirectory, folderName)
317+
err := os.Mkdir(folderPath, 0755)
318+
require.Nil(t, err, "Could not create folder "+folderName)
319+
return folderPath
320+
}
321+
322+
func update_handler_env(fakeEnv *types.HandlerEnvironment, statusFolder string, configFolder string, eventsFolder string) {
323+
fakeEnv.HandlerEnvironment.StatusFolder = statusFolder
324+
fakeEnv.HandlerEnvironment.ConfigFolder = configFolder
325+
fakeEnv.HandlerEnvironment.EventsFolder = eventsFolder
326+
}
327+
304328
func install_handler(t *testing.T, fakeEnv types.HandlerEnvironment, tempDir string) {
305329
generic_handler_call(t, fakeEnv, tempDir, "install", types.CmdInstallTemplate, CmdInstall)
306330
}

internal/commandProcessor/commandProcessor.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"time"
1010

11+
"github.com/Azure/azure-extension-platform/pkg/handlerenv"
1112
"github.com/Azure/azure-extension-platform/pkg/logging"
1213
"github.com/Azure/run-command-handler-linux/internal/constants"
1314
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
@@ -19,6 +20,10 @@ import (
1920
"github.com/pkg/errors"
2021
)
2122

23+
var (
24+
handlerEnvironmentGetter func(name, version string) (he *handlerenv.HandlerEnvironment, _ error) = handlerenv.GetHandlerEnvironment
25+
)
26+
2227
func ProcessImmediateHandlerCommand(cmd types.Cmd, hs handlersettings.HandlerSettingsFile, extensionName string, seqNum int) error {
2328
ctx := initializeLogger(cmd)
2429
ctx = ctx.With("extensionName", extensionName)

internal/constants/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const (
2525

2626
StatusFileDirectory = "status"
2727

28+
ExtensionEventsDirectory = "events"
29+
2830
StatusFileExtension = ".status"
2931

3032
// The directory where the immediate run command status that have reached the terminal status are stored.

internal/immediatecmds/immediatecmds.go

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package immediatecmds
22

33
import (
4+
"fmt"
5+
6+
"github.com/Azure/azure-extension-platform/pkg/extensionevents"
47
"github.com/Azure/run-command-handler-linux/internal/constants"
58
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
69
"github.com/Azure/run-command-handler-linux/internal/service"
@@ -11,42 +14,53 @@ import (
1114

1215
// Updates the service definition if any immediate run command service exists.
1316
// The action is skipped if the service has already been upgraded.
14-
func Update(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int) (int, error) {
17+
func Update(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
1518
ctx.Log("message", "updating immediate run command")
1619
isInstalled, err := service.IsInstalled(ctx)
1720
if err != nil {
21+
errMessage := fmt.Sprintf("Failed to check if any runcommand service is installed: %v", err)
22+
extensionEvents.LogErrorEvent("immediateupdate", errMessage)
1823
return constants.ExitCode_CreateDataDirectoryFailed, errors.Wrap(err, "failed to check if any runcommand service is installed")
1924
}
2025

2126
if isInstalled {
22-
err = service.Register(ctx)
27+
err = service.Register(ctx, extensionEvents)
2328
if err != nil {
29+
errMessage := fmt.Sprintf("Failed to upgrade run command service: %v", err)
30+
extensionEvents.LogErrorEvent("immediateupdate", errMessage)
2431
return constants.ExitCode_UpgradeInstalledServiceFailed, errors.Wrap(err, "failed to upgrade run command service")
2532
}
2633
}
2734

2835
return constants.ExitCode_Okay, nil
2936
}
3037

31-
func Disable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int) (int, error) {
38+
func Disable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
3239
isInstalled, err := service.IsInstalled(ctx)
3340
if err != nil {
41+
errMessage := fmt.Sprintf("Failed to check if runcommand service is installed: %v", err)
42+
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
3443
return constants.ExitCode_DisableInstalledServiceFailed, errors.Wrap(err, "failed to check if runcommand service is installed")
3544
}
3645

3746
if isInstalled {
3847
isEnabled, err := service.IsEnabled(ctx)
3948
if err != nil {
49+
errMessage := fmt.Sprintf("Failed to check if service is enabled: %v", err)
50+
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
4051
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err, "failed to check if service is enabled")
4152
}
4253

4354
if isEnabled {
44-
err := service.Disable(ctx)
55+
err := service.Disable(ctx, extensionEvents)
4556
if err != nil {
57+
errMessage := fmt.Sprintf("Failed to disable run command service: %v", err)
58+
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
4659
return constants.ExitCode_DisableInstalledServiceFailed, errors.Wrap(err, "failed to disable run command service")
4760
}
4861
} else {
4962
ctx.Log("message", "Service installed but already got disabled. Skipping request to disable")
63+
extensionEvents.LogInformationalEvent("immediatedisable", "Service installed but already got disabled. Skipping request to disable")
5064
}
5165
}
5266

@@ -58,51 +72,64 @@ func Install() (int, error) {
5872
return constants.ExitCode_Okay, nil
5973
}
6074

61-
func Uninstall(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int) (int, error) {
75+
func Uninstall(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
6276
ctx.Log("message", "proceeding to uninstall immediate run command")
6377
isInstalled, err := service.IsInstalled(ctx)
6478
if err != nil {
79+
errMessage := fmt.Sprintf("Failed to check if runcommand service is installed: %v", err)
80+
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
6581
return constants.ExitCode_RemoveDataDirectoryFailed, errors.Wrap(err, "failed to check if runcommand service is installed")
6682
}
6783

6884
if isInstalled {
69-
error := service.DeRegister(ctx)
85+
error := service.DeRegister(ctx, extensionEvents)
7086
if error != nil {
87+
errMessage := fmt.Sprintf("Failed to uninstall run command service: %v", error)
88+
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
7189
return constants.ExitCode_UninstallInstalledServiceFailed, errors.Wrap(err, "failed to uninstall run command service")
7290
}
7391
}
7492
return constants.ExitCode_Okay, nil
7593
}
7694

77-
func Enable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, cfg handlersettings.HandlerSettings) (int, error) {
95+
func Enable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, cfg handlersettings.HandlerSettings, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
7896
// If installService == true, then install RunCommand as a service
7997
if cfg.InstallAsService() {
8098
isInstalled, err2 := service.IsInstalled(ctx)
8199
if err2 != nil {
82100
ctx.Log("message", "could not check if service is already installed. Proceeding to overwrite configuration file to make sure it gets installed.")
101+
extensionEvents.LogErrorEvent("immediateenable", "could not check if service is already installed. Proceeding to overwrite configuration file to make sure it gets installed.")
83102
}
84103

85104
if !isInstalled {
86-
err3 := service.Register(ctx)
105+
err3 := service.Register(ctx, extensionEvents)
87106
if err3 != nil {
107+
errMessage := fmt.Sprintf("Failed to install RunCommand as a service: %v", err3)
108+
extensionEvents.LogErrorEvent("immediateenable", errMessage)
88109
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err3, "failed to install RunCommand as a service")
89110
}
90111
} else {
91112
isEnabled, err3 := service.IsEnabled(ctx)
92113
if err3 != nil {
114+
errMessage := fmt.Sprintf("Failed to check if service is already enabled: %v", err3)
115+
extensionEvents.LogErrorEvent("immediateenable", errMessage)
93116
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err3, "failed to check if service is already enabled")
94117
}
95118

96119
if !isEnabled {
97-
err4 := service.Enable(ctx)
120+
err4 := service.Enable(ctx, extensionEvents)
98121

99122
if err4 != nil {
123+
errMessage := fmt.Sprintf("Failed to enable service: %v", err4)
124+
extensionEvents.LogErrorEvent("immediateenable", errMessage)
100125
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err4, "failed to enable service")
101126
}
102127

103-
err5 := service.Start(ctx)
128+
err5 := service.Start(ctx, extensionEvents)
104129

105130
if err5 != nil {
131+
errMessage := fmt.Sprintf("Failed to start service: %v", err5)
132+
extensionEvents.LogErrorEvent("immediateenable", errMessage)
106133
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err5, "failed to start service")
107134
}
108135
}

0 commit comments

Comments
 (0)