Skip to content

Commit

Permalink
Adding exec config command (e)
Browse files Browse the repository at this point in the history
Added a new `e` command that enables us to run the DataPower
`exec` command that calls and runs a configuration script.
  • Loading branch information
vvidovic-croz committed May 17, 2023
1 parent d641bd9 commit bf00bcc
Show file tree
Hide file tree
Showing 13 changed files with 257 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,15 @@ m - show all status messages saved in the history
s - auto-synchronize selected directories (local to DataPower)
S - save a running DataPower configuration
B - create and copy a secure backup of the appliance
e - run exec command on current or selected cfg file(s)
0 - cycle between different DataPower view modes
filestore mode view / object mode view / status mode view
- when using SOMA access changed objects are marked and object
changes can be shown using diff (d key)
? - show status information for the current DataPower object,
local directory or local file
P - show DataPower policy for the current DataPower object
(can be used only on service, policy, matches,rules & actions)
(can be used only on service, policy, matches, rules & actions)
exports the current DataPower object, analyzes it and
shows service, policy, matches, rules and actions for
the object
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ func showVersion() {

// help prints in-program help information to console.
func showHelp(exitStatus int) {
fmt.Println(help.Help)
fmt.Print(help.Help)

os.Exit(exitStatus)
}
3 changes: 2 additions & 1 deletion help/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ m - show all status messages saved in the history
s - auto-synchronize selected directories (local to DataPower)
S - save a running DataPower configuration
B - create and copy a secure backup of the appliance
e - run exec command on current or selected cfg file(s)
0 - cycle between different DataPower view modes
filestore mode view / object mode view / status mode view
- when using SOMA access changed objects are marked and object
changes can be shown using diff (d key)
? - show status information for the current DataPower object,
local directory or local file
P - show DataPower policy for the current DataPower object
(can be used only on service, policy, matches,rules & actions)
(can be used only on service, policy, matches, rules & actions)
exports the current DataPower object, analyzes it and
shows service, policy, matches, rules and actions for
the object
Expand Down
68 changes: 68 additions & 0 deletions repo/dp/dp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2062,6 +2062,74 @@ func (r *dpRepo) FlushCache(
}
}

// ExecConfig run exec dommand for a DataPower configuration script.
func (r *dpRepo) ExecConfig(itemConfig *model.ItemConfig) error {
logging.LogDebugf("repo/dp/ExecConfig(%v)", itemConfig)

switch r.dataPowerAppliance.DpManagmentInterface() {
case config.DpInterfaceRest:
execConfigRequestJSON := fmt.Sprintf(`{"ExecConfig":{"URL":"%s"}}`, itemConfig.Path)
resultText, _, err := r.restPostForResult(
"/mgmt/actionqueue/"+itemConfig.DpDomain,
execConfigRequestJSON,
"/ExecConfig",
"Operation completed.",
"/ExecConfig")
if err != nil {
return err
}

logging.LogDebugf("repo/dp/ExecConfig(), resultText: '%s'", resultText)

return nil

case config.DpInterfaceSoma:
somaRequest := fmt.Sprintf(`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:man="http://www.datapower.com/schemas/management">
<soapenv:Body>
<man:request domain="%s">
<man:do-action><ExecConfig><URL>%s</URL></ExecConfig></man:do-action>
</man:request>
</soapenv:Body>
</soapenv:Envelope>`, itemConfig.DpDomain, itemConfig.Path)
response, err := r.soma(somaRequest)
if err != nil {
return err
}
result, err := parseSOMAFindOne(response, "//*[local-name()='response']/*[local-name()='result']")
logging.LogDebugf("repo/dp/ExecConfig(), result: '%v'", result)
if result != "OK" {
return errs.Errorf("DataPower exec config error: '%v'", result)
}
return nil

default:
logging.LogDebug("repo/dp/ExecConfig(), using neither REST neither SOMA.")
return errs.Error("DataPower management interface not set.")
}

// <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
// <env:Body>
// <dp:response xmlns:dp="http://www.datapower.com/schemas/management">
// <dp:timestamp>2023-02-06T10:52:04-05:00</dp:timestamp>
// <dp:result>
// <error-log>
// <dp:log-event level="error">Unable to execute config:///default.cf - must be text file.</dp:log-event>
// </error-log>
// </dp:result>
// </dp:response>
// </env:Body>
// </env:Envelope>
// <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
// <env:Body>
// <dp:response xmlns:dp="http://www.datapower.com/schemas/management">
// <dp:timestamp>2023-02-06T11:06:01-05:00</dp:timestamp>
// <dp:result>OK</dp:result>
// </dp:response>
// </env:Body>
// </env:Envelope>
}

// GetManagementInterface returns current DataPower management interface used.
func (r *dpRepo) GetManagementInterface() string {
return r.dataPowerAppliance.DpManagmentInterface()
Expand Down
48 changes: 48 additions & 0 deletions repo/dp/dp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2212,3 +2212,51 @@ func TestGetStatus(t *testing.T) {
assert.Equals(t, "GetStatus", string(statusBytes), wantStatus)
})
}

func TestExecConfig(t *testing.T) {
itemToExec := model.ItemConfig{Type: model.ItemFile,
DpDomain: "MyExecDomain", DpFilestore: "local:", Path: "local:/config-ok.cfg"}

t.Run("ExecConfig no REST/SOMA", func(t *testing.T) {
clearRepo()

err := Repo.ExecConfig(&itemToExec)
assert.Equals(t, "ExecConfig", err, errs.Error("DataPower management interface not set."))
})

itemToExec.Path = "local:/config-err.cfg"
t.Run("ExecConfig REST Error", func(t *testing.T) {
clearRepo()
Repo.dataPowerAppliance.RestUrl = testRestURL

err := Repo.ExecConfig(&itemToExec)
assert.Equals(t, "ExecConfig", err, errs.Error("Unexpected response from server."))
})

itemToExec.Path = "local:/config-ok.cfg"
t.Run("ExecConfig REST OK", func(t *testing.T) {
clearRepo()
Repo.dataPowerAppliance.RestUrl = testRestURL

err := Repo.ExecConfig(&itemToExec)
assert.Nil(t, "ExecConfig", err)
})

itemToExec.Path = "local:/config-err.cfg"
t.Run("ExecConfig SOMA Error", func(t *testing.T) {
clearRepo()
Repo.dataPowerAppliance.SomaUrl = testSomaURL

err := Repo.ExecConfig(&itemToExec)
assert.Equals(t, "ExecConfig", err, errs.Error("DataPower exec config error: 'Unable to execute local:/config-err.cfg - must be text file.'"))
})

itemToExec.Path = "local:/config-ok.cfg"
t.Run("ExecConfig SOMA OK", func(t *testing.T) {
clearRepo()
Repo.dataPowerAppliance.SomaUrl = testSomaURL

err := Repo.ExecConfig(&itemToExec)
assert.Nil(t, "ExecConfig", err)
})
}
28 changes: 28 additions & 0 deletions repo/dp/dpmock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"regexp"
"strings"

"github.com/croz-ltd/dpcmder/utils/errs"
)
Expand Down Expand Up @@ -68,6 +69,17 @@ func (nr mockRequester) httpRequest(dpa dpApplicance, urlFullPath, method, body
default:
return "", errs.Errorf("dpmock_test: Unrecognized method '%s'", method)
}
case "https://my_dp_host:5554/mgmt/actionqueue/MyExecDomain":
switch method {
case "POST":
if strings.Contains(body, "config-ok") {
content, err = ioutil.ReadFile("testdata/ExecConfig_ok.json")
} else {
content, err = ioutil.ReadFile("testdata/ExecConfig_error.json")
}
default:
return "", errs.Errorf("dpmock_test: Unrecognized method '%s'", method)
}
case "https://my_dp_host:5554/mgmt/actionqueue/tmp/pending/Export-20200228T061406Z-2":
content, err = ioutil.ReadFile("testdata/export-svc-pending-get.json")
case "https://my_dp_host:5554/mgmt/status/":
Expand Down Expand Up @@ -130,6 +142,14 @@ func (nr mockRequester) httpRequest(dpa dpApplicance, urlFullPath, method, body
if len(matches) == 1 {
opAction = "SecureBackup"
}

if len(matches) == 0 {
r = regexp.MustCompile(`.*<ExecConfig>.*`)
matches = r.FindStringSubmatch(body)
if len(matches) == 1 {
opAction = "ExecConfig"
}
}
}
}

Expand Down Expand Up @@ -180,6 +200,14 @@ func (nr mockRequester) httpRequest(dpa dpApplicance, urlFullPath, method, body
} else {
content, err = ioutil.ReadFile("testdata/SecureBackup_ok.xml")
}
case opTag == "do-action" && opAction == "ExecConfig":
r = regexp.MustCompile(`.*config-err.*`)
matches = r.FindStringSubmatch(body)
if len(matches) == 1 {
content, err = ioutil.ReadFile("testdata/ExecConfig_error.xml")
} else {
content, err = ioutil.ReadFile("testdata/ExecConfig_ok.xml")
}
default:
fmt.Printf("dpmock_test: Unrecognized SOMA request opTag: '%s', "+
"opClass: '%s', opObjClass: '%s', opLayoutOnly: '%s', opFilePath: '%s'.\n",
Expand Down
12 changes: 12 additions & 0 deletions repo/dp/testdata/ExecConfig_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"_links": {
"self": {
"href": "/mgmt/actionqueue/tmp"
}
},
"error": [
"Bad request.",
"Unable to execute local:/config-err.cfg - must be text file.",
" exec config:/matko23.cfg"
]
}
12 changes: 12 additions & 0 deletions repo/dp/testdata/ExecConfig_error.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<dp:response xmlns:dp="http://www.datapower.com/schemas/management">
<dp:timestamp>2023-05-17T05:07:12-04:00</dp:timestamp>
<dp:result>
<error-log>
<dp:log-event level="error">Unable to execute local:/config-err.cfg - must be text file.</dp:log-event>
</error-log>
</dp:result>
</dp:response>
</env:Body>
</env:Envelope>
12 changes: 12 additions & 0 deletions repo/dp/testdata/ExecConfig_ok.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"_links": {
"self": {
"href": "/mgmt/actionqueue/tmp"
},
"doc": {
"href": "/mgmt/docs/actionqueue"
}
},
"ExecConfig": "Operation completed.",
"script-log": ""
}
8 changes: 8 additions & 0 deletions repo/dp/testdata/ExecConfig_ok.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<dp:response xmlns:dp="http://www.datapower.com/schemas/management">
<dp:timestamp>2023-05-17T05:07:29-04:00</dp:timestamp>
<dp:result>OK</dp:result>
</dp:response>
</env:Body>
</env:Envelope>
15 changes: 10 additions & 5 deletions repo/localfs/localfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ package localfs

import (
"fmt"
"github.com/croz-ltd/dpcmder/config"
"github.com/croz-ltd/dpcmder/model"
"github.com/croz-ltd/dpcmder/utils/errs"
"github.com/croz-ltd/dpcmder/utils/logging"
"github.com/croz-ltd/dpcmder/utils/paths"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"

"github.com/croz-ltd/dpcmder/config"
"github.com/croz-ltd/dpcmder/model"
"github.com/croz-ltd/dpcmder/utils/errs"
"github.com/croz-ltd/dpcmder/utils/logging"
"github.com/croz-ltd/dpcmder/utils/paths"
)

type localRepo struct {
Expand Down Expand Up @@ -211,6 +212,10 @@ file mode: %s`,
return []byte(result), nil
}

func (r localRepo) ExecConfig(itemConfig *model.ItemConfig) error {
return errs.Error("Can't exec configuration on local machine.")
}

// Tree represents file/dir with all it's children and modification time.
type Tree struct {
Dir bool
Expand Down
1 change: 1 addition & 0 deletions repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ type Repo interface {
Delete(currentView *model.ItemConfig, itemType model.ItemType, parentPath, fileName string) (bool, error)
GetViewConfigByPath(currentView *model.ItemConfig, dirPath string) (*model.ItemConfig, error)
GetItemInfo(itemConfig *model.ItemConfig) ([]byte, error)
ExecConfig(itemConfig *model.ItemConfig) error
}
53 changes: 53 additions & 0 deletions ui/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ func ProcessInputEvent(event tcell.Event) error {
err = saveDataPowerConfig(&workingModel)
case c == 'm':
err = showStatusMessages(workingModel.Statuses())
case c == 'e':
err = execConfigFile(&workingModel)
case c == '0':
err = toggleObjectMode(&workingModel)
case c == '?':
Expand Down Expand Up @@ -2167,6 +2169,57 @@ func syncLocalToDpLater(tree, treeOld *localfs.Tree) bool {
return changesMade
}

// execConfigFile switches between (default) filestore mode, object mode and
// status mode for the DataPower view.
func execConfigFile(m *model.Model) error {
logging.LogDebugf("worker/execConfigFile(), dp.Repo.DpViewMode: %s", dp.Repo.DpViewMode)

side := m.CurrSide()
// viewConfig := m.ViewConfig(side)
switch side {
case model.Left:
itemsToExec := getSelectedOrCurrent(m)
pathsToExec := make([]string, len(itemsToExec))
for idx, item := range itemsToExec {
ci := item.Config
pathsToExec[idx] = ci.Path
switch item.Config.Type {
case model.ItemFile:
default:
return errs.Errorf("Can't exec item '%s' (%s)",
ci.Name, ci.Type.UserFriendlyString())
}
}

res := "n"
dialogResult := askUserInput(
fmt.Sprintf("Confirm exec files %v (y/n): ",
pathsToExec), "", false)
if dialogResult.dialogSubmitted {
res = dialogResult.inputAnswer
}
logging.LogDebugf("ui/execConfigFile(), confirm exec: '%s'", res)
if res == "y" {
for _, item := range itemsToExec {
showProgressDialogf("Running exec command '%s' file from DataPower...", item.Name)
err := repos[m.CurrSide()].ExecConfig(item.Config)
if err != nil {
hideProgressDialog()
return err
}
}
hideProgressDialog()
updateStatusf("Exec config files success: %v", pathsToExec)
}

default:
logging.LogDebug("worker/execConfigFile(), To exec config file select config file in the DataPower view.")
return errs.Error("To exec config file select config file in the DataPower view.")
}

return nil
}

// toggleObjectMode switches between (default) filestore mode, object mode and
// status mode for the DataPower view.
func toggleObjectMode(m *model.Model) error {
Expand Down

0 comments on commit bf00bcc

Please sign in to comment.