Browse Source

EventManager commands: allow to retrieve env vars from the process env

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 1 year ago
parent
commit
9a7a3b00dc

+ 9 - 1
internal/common/eventmanager.go

@@ -1464,7 +1464,15 @@ func executeCommandRuleAction(c dataprovider.EventActionCommandConfig, params *E
 	cmd := exec.CommandContext(ctx, c.Cmd, args...)
 	cmd := exec.CommandContext(ctx, c.Cmd, args...)
 	cmd.Env = []string{}
 	cmd.Env = []string{}
 	for _, keyVal := range c.EnvVars {
 	for _, keyVal := range c.EnvVars {
-		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", keyVal.Key, replaceWithReplacer(keyVal.Value, replacer)))
+		if keyVal.Value == "$" {
+			val := os.Getenv(keyVal.Key)
+			if val == "" {
+				eventManagerLog(logger.LevelDebug, "empty value for environment variable %q", keyVal.Key)
+			}
+			cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", keyVal.Key, val))
+		} else {
+			cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", keyVal.Key, replaceWithReplacer(keyVal.Value, replacer)))
+		}
 	}
 	}
 
 
 	startTime := time.Now()
 	startTime := time.Now()

+ 97 - 0
internal/common/protocol_test.go

@@ -4869,6 +4869,92 @@ func TestEventRulePreDownloadUpload(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 }
 }
 
 
+func TestEventActionCommandEnvVars(t *testing.T) {
+	if runtime.GOOS == osWindows {
+		t.Skip("this test is not available on Windows")
+	}
+	envName := "MY_ENV"
+	uploadScriptPath := filepath.Join(os.TempDir(), "upload.sh")
+
+	err := os.WriteFile(uploadScriptPath, getUploadScriptEnvContent(envName), 0755)
+	assert.NoError(t, err)
+	a1 := dataprovider.BaseEventAction{
+		Name: "action1",
+		Type: dataprovider.ActionTypeCommand,
+		Options: dataprovider.BaseEventActionOptions{
+			CmdConfig: dataprovider.EventActionCommandConfig{
+				Cmd:     uploadScriptPath,
+				Timeout: 10,
+				EnvVars: []dataprovider.KeyValue{
+					{
+						Key:   envName,
+						Value: "$",
+					},
+				},
+			},
+		},
+	}
+	action1, _, err := httpdtest.AddEventAction(a1, http.StatusCreated)
+	assert.NoError(t, err)
+
+	r1 := dataprovider.EventRule{
+		Name:    "test rule1",
+		Status:  1,
+		Trigger: dataprovider.EventTriggerFsEvent,
+		Conditions: dataprovider.EventConditions{
+			FsEvents: []string{"upload"},
+		},
+		Actions: []dataprovider.EventAction{
+			{
+				BaseEventAction: dataprovider.BaseEventAction{
+					Name: action1.Name,
+				},
+				Order: 1,
+				Options: dataprovider.EventActionOptions{
+					ExecuteSync: true,
+				},
+			},
+		},
+	}
+	rule1, _, err := httpdtest.AddEventRule(r1, http.StatusCreated)
+	assert.NoError(t, err)
+
+	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
+	assert.NoError(t, err)
+
+	conn, client, err := getSftpClient(user)
+	if assert.NoError(t, err) {
+		defer conn.Close()
+		defer client.Close()
+
+		err = writeSFTPFileNoCheck(testFileName, 100, client)
+		assert.Error(t, err)
+	}
+
+	os.Setenv(envName, "1")
+	defer os.Unsetenv(envName)
+
+	conn, client, err = getSftpClient(user)
+	if assert.NoError(t, err) {
+		defer conn.Close()
+		defer client.Close()
+
+		err = writeSFTPFileNoCheck(testFileName, 100, client)
+		assert.NoError(t, err)
+	}
+
+	_, err = httpdtest.RemoveEventRule(rule1, http.StatusOK)
+	assert.NoError(t, err)
+	_, err = httpdtest.RemoveEventAction(action1, http.StatusOK)
+	assert.NoError(t, err)
+	_, err = httpdtest.RemoveUser(user, http.StatusOK)
+	assert.NoError(t, err)
+	err = os.RemoveAll(user.GetHomeDir())
+	assert.NoError(t, err)
+	err = os.Remove(uploadScriptPath)
+	assert.NoError(t, err)
+}
+
 func TestFsActionCopy(t *testing.T) {
 func TestFsActionCopy(t *testing.T) {
 	a1 := dataprovider.BaseEventAction{
 	a1 := dataprovider.BaseEventAction{
 		Name: "a1",
 		Name: "a1",
@@ -8828,6 +8914,17 @@ func writeSFTPFileNoCheck(name string, size int64, client *sftp.Client) error {
 	return f.Close()
 	return f.Close()
 }
 }
 
 
+func getUploadScriptEnvContent(envVar string) []byte {
+	content := []byte("#!/bin/sh\n\n")
+	content = append(content, []byte(fmt.Sprintf("if [ -z \"$%s\" ]\n", envVar))...)
+	content = append(content, []byte("then\n")...)
+	content = append(content, []byte("    exit 1\n")...)
+	content = append(content, []byte("else\n")...)
+	content = append(content, []byte("    exit 0\n")...)
+	content = append(content, []byte("fi\n")...)
+	return content
+}
+
 func getUploadScriptContent(movedPath, logFilePath string, exitStatus int) []byte {
 func getUploadScriptContent(movedPath, logFilePath string, exitStatus int) []byte {
 	content := []byte("#!/bin/sh\n\n")
 	content := []byte("#!/bin/sh\n\n")
 	content = append(content, []byte("sleep 1\n")...)
 	content = append(content, []byte("sleep 1\n")...)

+ 1 - 1
templates/webadmin/eventaction.html

@@ -407,7 +407,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     <b>Environment variables</b>
                     <b>Environment variables</b>
                 </div>
                 </div>
                 <div class="card-body">
                 <div class="card-body">
-                    <h6 class="card-title mb-4">Placeholders are supported in values.</h6>
+                    <h6 class="card-title mb-4">Placeholders are supported in values. Setting the value to "$" without quotes means retrieving the key from the environment.</h6>
                     <div class="form-group row">
                     <div class="form-group row">
                         <div class="col-md-12 form_field_cmd_env_outer">
                         <div class="col-md-12 form_field_cmd_env_outer">
                             {{range $idx, $val := .Action.Options.CmdConfig.EnvVars}}
                             {{range $idx, $val := .Action.Options.CmdConfig.EnvVars}}