Skip to content

Commit fac6880

Browse files
committed
More unit test fixes
1 parent 1469f2d commit fac6880

11 files changed

Lines changed: 71 additions & 55 deletions

File tree

internal/cleanup/cleanup.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package cleanup
22

33
import (
44
"fmt"
5+
"os"
56
"path/filepath"
7+
"strconv"
68

9+
"github.com/Azure/azure-extension-platform/pkg/utils"
710
"github.com/Azure/run-command-handler-linux/internal/constants"
811
"github.com/Azure/run-command-handler-linux/internal/types"
912
"github.com/Azure/run-command-handler-linux/pkg/linuxutils"
@@ -38,28 +41,28 @@ func deleteAllScriptsAndSettings(ctx *log.Context, metadata types.RCMetadata, h
3841
}
3942

4043
func deleteScriptsAndSettingsExceptMostRecent(ctx *log.Context, metadata types.RCMetadata, h types.HandlerEnvironment, runAsUser string) {
41-
// runtimeSettingsRegexFormat := metadata.ExtName + ".\\d+.settings"
42-
// runtimeSettingsLastSeqNumFormat := metadata.ExtName + ".%d.settings"
44+
runtimeSettingsRegexFormat := metadata.ExtName + ".\\d+.settings"
45+
runtimeSettingsLastSeqNumFormat := metadata.ExtName + ".%d.settings"
4346

44-
// // check if directory exists
45-
// _, err := os.Open(metadata.DownloadPath)
46-
// if err == nil {
47-
// err := utils.TryClearExtensionScriptsDirectoriesAndSettingsFilesExceptMostRecent(metadata.DownloadPath, h.HandlerEnvironment.ConfigFolder, "",
48-
// uint64(metadata.SeqNum), runtimeSettingsRegexFormat, runtimeSettingsLastSeqNumFormat)
49-
// if err != nil {
50-
// ctx.Log("event", "could not clear settings and script files", "error", err)
51-
// }
52-
// } else {
53-
// ctx.Log("message", "directory does not exist. Skipping cleanup")
54-
// }
47+
// check if directory exists
48+
_, err := os.Open(metadata.DownloadPath)
49+
if err == nil {
50+
err := utils.TryClearExtensionScriptsDirectoriesAndSettingsFilesExceptMostRecent(metadata.DownloadPath, h.HandlerEnvironment.ConfigFolder, "",
51+
uint64(metadata.SeqNum), runtimeSettingsRegexFormat, runtimeSettingsLastSeqNumFormat)
52+
if err != nil {
53+
ctx.Log("event", "could not clear settings and script files", "error", err)
54+
}
55+
} else {
56+
ctx.Log("message", "directory does not exist. Skipping cleanup")
57+
}
5558

56-
// if runAsUser != "" {
57-
// runAsDownloadParent := filepath.Join(fmt.Sprintf(constants.RunAsDir, runAsUser), metadata.DownloadDir)
58-
// seqNumString := strconv.Itoa(metadata.SeqNum)
59-
// ctx.Log("message", "removing all files from the download 'runas' directory "+runAsDownloadParent)
60-
// err = utils.TryDeleteDirectoriesExcept(runAsDownloadParent, seqNumString)
61-
// if err != nil {
62-
// ctx.Log("event", "could not clear runas script")
63-
// }
64-
// }
59+
if runAsUser != "" {
60+
runAsDownloadParent := filepath.Join(fmt.Sprintf(constants.RunAsDir, runAsUser), metadata.DownloadDir)
61+
seqNumString := strconv.Itoa(metadata.SeqNum)
62+
ctx.Log("message", "removing all files from the download 'runas' directory "+runAsDownloadParent)
63+
err = utils.TryDeleteDirectoriesExcept(runAsDownloadParent, seqNumString)
64+
if err != nil {
65+
ctx.Log("event", "could not clear runas script")
66+
}
67+
}
6568
}

internal/cmds/cmds.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,22 @@ func enable(ctx *log.Context, h types.HandlerEnvironment, report *types.RunComma
202202
}
203203

204204
dir := filepath.Join(metadata.DownloadPath, fmt.Sprintf("%d", metadata.SeqNum))
205-
scriptFilePath, err := downloadScript(ctx, dir, &cfg)
206-
if err != nil {
205+
scriptFilePath, ewc := downloadScript(ctx, dir, &cfg)
206+
if ewc != nil {
207207
errMessage := fmt.Sprintf("Failed to download script: %v due to: %v", download.GetUriForLogging(cfg.ScriptURI()), err)
208208
extensionEvents.LogErrorEvent("enable", errMessage)
209209
return "",
210210
"",
211-
vmextension.CreateWrappedErrorWithClarification(err, fmt.Sprintf("File downloads failed. Use either a public script URI that points to .sh file, Azure storage blob SAS URI or storage blob accessible by a managed identity and retry. If managed identity is used, make sure it has been given access to container of storage blob '%s' with 'Storage Blob Data Reader' role assignment. In case of user-assigned identity, make sure you add it under VM's identity. For more info, refer https://aka.ms/RunCommandManagedLinux", download.GetUriForLogging(cfg.ScriptURI()))),
211+
vmextension.CreateWrappedErrorWithClarification(ewc, fmt.Sprintf("File downloads failed. Use either a public script URI that points to .sh file, Azure storage blob SAS URI or storage blob accessible by a managed identity and retry. If managed identity is used, make sure it has been given access to container of storage blob '%s' with 'Storage Blob Data Reader' role assignment. In case of user-assigned identity, make sure you add it under VM's identity. For more info, refer https://aka.ms/RunCommandManagedLinux", download.GetUriForLogging(cfg.ScriptURI()))),
212212
constants.FileDownload_GenericError
213213
}
214214

215-
err = downloadArtifacts(ctx, dir, &cfg)
216-
if err != nil {
217-
errMessage := fmt.Sprintf("Failed to download artifacts: %v", err)
215+
ewc = downloadArtifacts(ctx, dir, &cfg)
216+
if ewc != nil {
217+
errMessage := fmt.Sprintf("Failed to download artifacts: %v", ewc)
218218
extensionEvents.LogErrorEvent("enable", errMessage)
219219
return "", "",
220-
vmextension.CreateWrappedErrorWithClarification(err, "Artifact downloads failed. Use either a public artifact URI that points to .sh file, Azure storage blob SAS URI, or storage blob accessible by a managed identity and retry."),
220+
vmextension.CreateWrappedErrorWithClarification(ewc, "Artifact downloads failed. Use either a public artifact URI that points to .sh file, Azure storage blob SAS URI, or storage blob accessible by a managed identity and retry."),
221221
constants.ArtifactDownload_GenericError
222222
}
223223

internal/cmds/cmds_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import (
1212
"strings"
1313
"testing"
1414

15+
osexec "os/exec"
16+
1517
"github.com/Azure/azure-extension-platform/pkg/extensionevents"
1618
"github.com/Azure/azure-extension-platform/pkg/handlerenv"
1719
"github.com/Azure/azure-extension-platform/pkg/logging"
1820
"github.com/Azure/azure-extension-platform/vmextension"
1921
"github.com/Azure/run-command-handler-linux/internal/constants"
22+
"github.com/Azure/run-command-handler-linux/internal/exec"
2023
"github.com/Azure/run-command-handler-linux/internal/files"
2124
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
2225
"github.com/Azure/run-command-handler-linux/internal/settings"
@@ -436,6 +439,13 @@ func Test_runCmd_success(t *testing.T) {
436439
require.Nil(t, err)
437440
defer os.RemoveAll(dir)
438441

442+
orig := exec.FnRunCommand
443+
defer func() { exec.FnRunCommand = orig }()
444+
exec.FnRunCommand = func(_ *osexec.Cmd) error {
445+
// Success
446+
return nil
447+
}
448+
439449
metadata := types.NewRCMetadata("extName", 0, constants.DownloadFolder, DataDir)
440450
err, exitCode := runCmd(log.NewContext(log.NewNopLogger()), dir, "", &handlersettings.HandlerSettings{
441451
PublicSettings: handlersettings.PublicSettings{Source: &handlersettings.ScriptSource{Script: script}},

internal/commandProcessor/commandProcessor.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func ProcessHandlerCommandWithDetails(ctx *log.Context, cmd types.Cmd, hEnv type
101101
statusToReport := types.StatusSuccess
102102

103103
// Add an error clarification if we have one
104-
var ewc vmextension.ErrorWithClarification
104+
var ewc *vmextension.ErrorWithClarification
105105
if errors.As(cmdInvokeError, &ewc) {
106106
instView.ErrorClarificationValue = ewc.ErrorCode
107107
}
@@ -113,6 +113,11 @@ func ProcessHandlerCommandWithDetails(ctx *log.Context, cmd types.Cmd, hEnv type
113113
}
114114

115115
fnReportInstanceView(ctx, hEnv, metadata, statusToReport, cmd, &instView)
116+
117+
if err == nil {
118+
return nil
119+
}
120+
116121
return errors.Wrapf(err, "command execution failed")
117122
} else { // No error. Succeeded
118123
instView.ExecutionMessage = "Execution completed"

internal/commandProcessor/commandProcessor_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,20 +202,15 @@ func Test_ProcessHandlerCommandWithDetails_Failure_WithClarification(t *testing.
202202
return nil
203203
}
204204

205-
ewc := vmextension.ErrorWithClarification{
206-
ErrorCode: 1234,
207-
Err: errors.New("the chipmunks are upset"),
208-
}
209-
210205
mockFunc := types.CmdFunctions{
211206
Invoke: func(_ *log.Context, _ types.HandlerEnvironment, iv *types.RunCommandInstanceView, _ types.RCMetadata, _ types.Cmd) (string, string, error, int) {
212-
return "x", "y", ewc, 3
207+
return "x", "y", vmextension.NewErrorWithClarificationPtr(1234, errors.New("the chipmunks are upset")), 3
213208
},
214209
}
215210

216211
orig := fnGetHandlerSettings
217212
defer func() { fnGetHandlerSettings = orig }()
218-
fnGetHandlerSettings = func(string, string, int, *log.Context) (handlersettings.HandlerSettings, error) {
213+
fnGetHandlerSettings = func(string, string, int, *log.Context) (handlersettings.HandlerSettings, *vmextension.ErrorWithClarification) {
219214
return handlersettings.HandlerSettings{
220215
PublicSettings: handlersettings.PublicSettings{
221216
TreatFailureAsDeploymentFailure: false,

internal/exec/exec.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var (
2828
fnOsMkDirAll = os.MkdirAll
2929
fnOsOpenFile = os.OpenFile
3030
fnOsSetEnv = os.Setenv
31-
fnRunCommand = runCommand
31+
FnRunCommand = runCommand
3232
fnUserLookup = user.Lookup
3333
)
3434

@@ -140,7 +140,7 @@ func Exec(ctx *log.Context, cmd, workdir string, stdout, stderr io.WriteCloser,
140140
command.Dir = workdir
141141
command.Stdout = stdout
142142
command.Stderr = stderr
143-
err = fnRunCommand(command)
143+
err = FnRunCommand(command)
144144
if err != nil {
145145
exitErr, ok := err.(*exec.ExitError)
146146
if ok {

internal/exec/exec_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestExec_AlwaysClosesStreams(t *testing.T) {
4747
errw := newCloseRecorder()
4848

4949
// Force runCommand to return error to ensure closures happen on error path.
50-
fnRunCommand = func(_ *exec.Cmd) error {
50+
FnRunCommand = func(_ *exec.Cmd) error {
5151
return errors.New("the chipmunks have revolted")
5252
}
5353

@@ -85,7 +85,7 @@ func TestExec_RunAsUser_OpenSourceScriptFails_ReturnsOpenSourceFailed(t *testing
8585
return nil, errors.New("open failed")
8686
}
8787
// Ensure we don't accidentally reach execution
88-
fnRunCommand = func(_ *exec.Cmd) error {
88+
FnRunCommand = func(_ *exec.Cmd) error {
8989
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
9090
return nil
9191
}
@@ -114,7 +114,7 @@ func TestExec_RunAsUser_CreateDestScriptFails_ReturnsOpenSourceFailed(t *testing
114114
fnOsCreate = func(_ string) (*os.File, error) {
115115
return nil, errors.New("create failed")
116116
}
117-
fnRunCommand = func(_ *exec.Cmd) error {
117+
FnRunCommand = func(_ *exec.Cmd) error {
118118
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
119119
return nil
120120
}
@@ -147,7 +147,7 @@ func TestExec_RunAsUser_CopyFails_ReturnsCopyFailed(t *testing.T) {
147147
fnIoCopy = func(_ io.Writer, _ io.Reader) (int64, error) {
148148
return 0, errors.New("the chipmunks do not copy")
149149
}
150-
fnRunCommand = func(_ *exec.Cmd) error {
150+
FnRunCommand = func(_ *exec.Cmd) error {
151151
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
152152
return nil
153153
}
@@ -179,7 +179,7 @@ func TestExec_RunAsUser_LookupUserFails_ReturnsRunAsUserLogonFailed(t *testing.T
179179
fnUserLookup = func(_ string) (*user.User, error) {
180180
return nil, errors.New("no such chipmunk")
181181
}
182-
fnRunCommand = func(_ *exec.Cmd) error {
182+
FnRunCommand = func(_ *exec.Cmd) error {
183183
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
184184
return nil
185185
}
@@ -210,7 +210,7 @@ func TestExec_RunAsUser_UidParseFails_ReturnsLookupUserUidFailed(t *testing.T) {
210210
fnUserLookup = func(_ string) (*user.User, error) {
211211
return &user.User{Uid: "not-an-int"}, nil
212212
}
213-
fnRunCommand = func(_ *exec.Cmd) error {
213+
FnRunCommand = func(_ *exec.Cmd) error {
214214
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
215215
return nil
216216
}
@@ -243,7 +243,7 @@ func TestExec_RunAsUser_ChownFails_ReturnsChangeOwnerFailed(t *testing.T) {
243243
fnOsChown = func(_ string, _ int, _ int) error {
244244
return errors.New("chown failed")
245245
}
246-
fnRunCommand = func(_ *exec.Cmd) error {
246+
FnRunCommand = func(_ *exec.Cmd) error {
247247
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
248248
return nil
249249
}
@@ -278,7 +278,7 @@ func TestExec_RunAsUser_ChmodFails_ReturnsChangePermissionsFailed(t *testing.T)
278278
return errors.New("chmod failed")
279279
}
280280

281-
fnRunCommand = func(_ *exec.Cmd) error {
281+
FnRunCommand = func(_ *exec.Cmd) error {
282282
t.Fatalf("fnRunCommand should not be called when RunAs setup fails")
283283
return nil
284284
}
@@ -539,7 +539,7 @@ func saveAndRestoreFns() func() {
539539
mkdirAll: fnOsMkDirAll,
540540
openFile: fnOsOpenFile,
541541
setEnv: fnOsSetEnv,
542-
runCommand: fnRunCommand,
542+
runCommand: FnRunCommand,
543543
userLookup: fnUserLookup,
544544
}
545545
return func() {
@@ -550,7 +550,7 @@ func saveAndRestoreFns() func() {
550550
fnOsMkDirAll = s.mkdirAll
551551
fnOsOpenFile = s.openFile
552552
fnOsSetEnv = s.setEnv
553-
fnRunCommand = s.runCommand
553+
FnRunCommand = s.runCommand
554554
fnUserLookup = s.userLookup
555555
}
556556
}

internal/files/files.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ func downloadAndProcessURL(ctx *log.Context, url, downloadDir string, fileName s
5555

5656
targetFilePath := filepath.Join(downloadDir, fileName)
5757

58-
var scriptSASDownloadErr error = nil
58+
var scriptSASDownloadErr *vmextension.ErrorWithClarification = nil
5959
var downloadedFilePath string = ""
6060
if scriptSAS != "" {
6161
if UseMockSASDownloadFailure {
62-
scriptSASDownloadErr = errors.New("Downloading script using SAS token failed.")
62+
scriptSASDownloadErr = vmextension.NewErrorWithClarificationPtr(42, errors.New("Downloading script using SAS token failed."))
6363
} else {
6464
downloadedFilePath, scriptSASDownloadErr = download.GetSASBlob(url, scriptSAS, downloadDir)
6565
}

internal/handlersettings/handlersettings.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package handlersettings
22

33
import (
4+
"github.com/Azure/azure-extension-platform/vmextension"
45
"github.com/go-kit/kit/log"
56
"github.com/pkg/errors"
67
)
@@ -11,7 +12,7 @@ var (
1112

1213
// parseAndValidateSettings reads configuration from configFolder, decrypts it,
1314
// runs JSON-schema and logical validation on it and returns it back.
14-
func ParseAndValidateSettings(ctx *log.Context, configFilePath string) (h HandlerSettings, _ error) {
15+
func ParseAndValidateSettings(ctx *log.Context, configFilePath string) (h HandlerSettings, _ *vmextension.ErrorWithClarification) {
1516
ctx.Log("event", "reading configuration from "+configFilePath)
1617
pubJSON, protJSON, err := readSettings(configFilePath)
1718
if err != nil {
@@ -36,7 +37,7 @@ func ParseAndValidateSettings(ctx *log.Context, configFilePath string) (h Handle
3637
// readSettings uses specified configFilePath (comes from HandlerEnvironment) to
3738
// decrypt and parse the public/protected settings of the extension handler into
3839
// JSON objects.
39-
func readSettings(configFilePath string) (pubSettingsJSON, protSettingsJSON map[string]interface{}, err error) {
40+
func readSettings(configFilePath string) (pubSettingsJSON, protSettingsJSON map[string]interface{}, err *vmextension.ErrorWithClarification) {
4041
pubSettingsJSON, protSettingsJSON, err = ReadSettings(configFilePath)
4142
return
4243
}

internal/handlersettings/utilities.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"path/filepath"
88

9+
"github.com/Azure/azure-extension-platform/vmextension"
910
"github.com/go-kit/kit/log"
1011
)
1112

@@ -35,7 +36,7 @@ func GetUriForLogging(uriString string) string {
3536
}
3637

3738
// Get handler settings from config folder. Example path: /var/lib/waagent/Microsoft.CPlat.Core.RunCommandHandlerLinux-1.3.2/config
38-
func GetHandlerSettings(configFolder string, extensionName string, sequenceNumber int, logContext *log.Context) (HandlerSettings, error) {
39+
func GetHandlerSettings(configFolder string, extensionName string, sequenceNumber int, logContext *log.Context) (HandlerSettings, *vmextension.ErrorWithClarification) {
3940
configPath := GetConfigFilePath(configFolder, sequenceNumber, extensionName)
4041
cfg, err := ParseAndValidateSettings(logContext, configPath)
4142
return cfg, err

0 commit comments

Comments
 (0)