Skip to content

Commit

Permalink
commit command
Browse files Browse the repository at this point in the history
  • Loading branch information
mihakralj committed Sep 27, 2023
1 parent 0a49963 commit 780ac15
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 70 deletions.
8 changes: 0 additions & 8 deletions clearversion.xml

This file was deleted.

35 changes: 31 additions & 4 deletions cmd/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,43 @@ var commitCmd = &cobra.Command{
fmt.Println("\nChanges to be commited:")
internal.PrintDocument(deltadoc, "opnsense")

internal.Log(2, "commiting %s to %s", stagingfile, configfile)
internal.Log(2, "commiting %s to %s and reloading all services", stagingfile, configfile)

// copy config.xml to /conf/backup dir
backupname := internal.GenerateBackupFilename()
bash = `sudo cp -f ` + configfile + ` /conf/backup/` + backupname + ` && sudo mv -f /conf/staging.xml ` + configfile
internal.ExecuteCmd(bash, host)

fmt.Println("time to reload OPNSense!")

//TODO: run php /usr/local/etc/rc.reload_all
include := "php -r \"require_once('/usr/local/etc/inc/config.inc'); require_once('/usr/local/etc/inc/interfaces.inc'); require_once('/usr/local/etc/inc/filter.inc'); require_once('/usr/local/etc/inc/auth.inc'); require_once('/usr/local/etc/inc/rrd.inc'); require_once('/usr/local/etc/inc/util.inc'); require_once('/usr/local/etc/inc/system.inc'); require_once('/usr/local/etc/inc/interfaces.inc'); "

var result string

result = internal.ExecuteCmd(include+"system_firmware_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_trust_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_login_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_cron_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_timezone_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_hostname_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_resolver_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"interfaces_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"system_routing_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"rrd_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"filter_configure(true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"plugins_configure('vpn', true); \"", host)
fmt.Println(result)
result = internal.ExecuteCmd(include+"plugins_configure('local', true); \"", host)
fmt.Println(result)

},
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ var exportCmd = &cobra.Command{
newdoc = olddoc
}

//TODO: add support for xml lists

deltadoc := internal.DiffXML(olddoc, newdoc, false)
internal.RemoveChgSpace(deltadoc.Root())
output := internal.ConfigToXML(deltadoc, path)
Expand Down
67 changes: 30 additions & 37 deletions cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ limitations under the License.
package cmd

import (
"bufio"
"fmt"
"io"
"os"

"github.com/beevik/etree"
Expand All @@ -30,70 +28,65 @@ var execute bool

// compareCmd represents the compare command
var importCmd = &cobra.Command{
Use: "import",
Use: "import [patch.xml]",
Short: `Import XML patch and stage it for configuraiton change`,
Long: `The 'import' command allows bulk import of configuration changes by injecting an XML patch file that specifies what to add, or delete in the current configuration. Patch file is in the standard XML format generated by the 'export' command, using namespace tags indicating the type of change (e.g., add:, del:).
The command reads the patch file from the standard input. You can pipe the patch file into this command:
cat patch.xml | opnsense import
Or insert patch using I/O redirection:
opnsense import < patch.xml
Once the patch is imported, it is added to currently staged changes in 'staging.xml'. You can review these changes using 'opnsense compare -c' and apply them using 'opnsense commit' when ready.`,
Once the patch is imported, it is added to currently staged changes in 'staging.xml'. You can review staged changes using 'opnsense compare --compact' and apply them using 'opnsense commit' when ready.`,

Run: func(cmd *cobra.Command, args []string) {
internal.SetFlags(verbose, force, host, configfile, nocolor, depth, xmlFlag, yamlFlag, jsonFlag)

patchdoc := etree.NewDocument()

stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
reader := bufio.NewReader(os.Stdin)
var output []rune
if len(args) > 0 {
//check parameters
if len(args) > 0 {
importfilename := args[0]
if _, err := os.Stat(importfilename); os.IsNotExist(err) {
internal.Log(1, "import file %s does not exist\n", importfilename)
}
// Read file contents into a string
fileContents, err := os.ReadFile(importfilename)
if err != nil {
internal.Log(1, "failed to read file %s: %v\n", importfilename, err)
return
}
fileString := string(fileContents)

for {
input, _, err := reader.ReadRune()
if err != nil && err == io.EOF {
break
err = patchdoc.ReadFromString(fileString)
if err != nil {
internal.Log(1, "%s is not an XML file", importfilename)
}
output = append(output, input)
}
err := patchdoc.ReadFromString(string(output))
if err != nil {
internal.Log(1, "received stdin is not in XML format")
}

} else {
internal.Log(1, "No data received on stdin, please pipe the XML file into this command")
internal.Log(1, "No patch XML file provided")
}

//TODO: add support for xml lists

internal.Checkos()
configdoc := internal.LoadXMLFile(configfile, host, false)

stagingdoc := internal.LoadXMLFile(stagingfile, host, true)
if stagingdoc == nil {
stagingdoc = internal.LoadXMLFile(stagingfile, host, true)
stagingdoc = configdoc.Copy()
}

internal.PatchElements(patchdoc.Root(), stagingdoc)
deltadoc := internal.DiffXML(configdoc, stagingdoc, false)

if !execute {
fmt.Println("Preview of modifications scheduled for imported into staging.xml:")
}
fmt.Println("Preview of patch scheduled for imported into staging.xml:")

internal.PrintDocument(deltadoc, "opnsense")

if execute {
internal.SaveXMLFile(stagingfile, stagingdoc, host, true)
fmt.Println("\nModifications imported into staging.xml")
}
internal.Log(2, "importing patch into staging.xml")
internal.SaveXMLFile(stagingfile, stagingdoc, host, true)
fmt.Println("\nModifications imported into staging.xml")
},
}

func init() {
importCmd.Flags().IntVarP(&depth, "depth", "d", 1, "Specifies number of depth levels of returned tree (default: 1)")
importCmd.Flags().BoolVarP(&execute, "execute", "e", false, "Apply the changes to the staging.xml, rather than just previewing them.")
importCmd.Flags().IntVarP(&depth, "depth", "d", 5, "Specifies number of depth levels of returned tree (default: 5)")
rootCmd.AddCommand(importCmd)
}
6 changes: 3 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

var (
Version string = "0.13.0"
Version string = "0.14.0"
verbose int
force bool
host string
Expand Down Expand Up @@ -84,8 +84,8 @@ To streamline remote operations, add your private key to the SSH agent using 'ss
}

func Execute() {
rootCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.CompletionOptions.DisableNoDescFlag = true
//rootCmd.CompletionOptions.DisableDefaultCmd = true
//rootCmd.CompletionOptions.DisableNoDescFlag = true
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Whoops. There was an error while executing CLI '%s'", err)
os.Exit(1)
Expand Down
13 changes: 10 additions & 3 deletions cmd/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,24 @@ The XPath parameter offers node targeting, enabling you to navigate to the exact
}
internal.EnumerateListElements(stagingdoc.Root())

//TODO: add support for xml lists

path := strings.Trim(args[0], "/")
if !strings.HasPrefix(path, "opnsense/") {
path = "opnsense/" + path
}
path = strings.ReplaceAll(path, "[", ".")
path = strings.ReplaceAll(path, "]", "")

if matched, _ := regexp.MatchString(`\[0\]`, path); matched {
internal.Log(1, "XPath indexing of elements starts with 1, not 0")
return
}

//find if path is refers to the list

//path = strings.ReplaceAll(path, "[", ".")
//path = strings.ReplaceAll(path, "]", "")

fmt.Println(path)

var attribute, value string
if len(args) == 2 {
if isAttribute(args[1]) {
Expand Down Expand Up @@ -103,6 +109,7 @@ The XPath parameter offers node targeting, enabling you to navigate to the exact
if element == nil {
element = stagingdoc.Root()
parts := strings.Split(path, "/")

for i, part := range parts {
part = fixXMLName(part)
if i == 0 && part == "opnsense" {
Expand Down
36 changes: 21 additions & 15 deletions internal/PatchXML.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,65 +21,71 @@ import (
"github.com/beevik/etree"
)

// PatchElements processes patch instructions in an XML element to modify a target XML document.
func PatchElements(patchEl *etree.Element, newDoc *etree.Document) {
// Check for nil inputs and log if detected
if patchEl == nil {
return
}

// Process elements
switch patchEl.Space {
case "add", "del":
// Process the patch element based on its namespace (either "add" or "del")
if patchEl.Space == "add" || patchEl.Space == "del" {
InjectElementAtPath(patchEl, newDoc)
}

// Process attributes
// Process patch attributes in the same way
for _, attr := range patchEl.Attr {
switch attr.Space {
case "add", "del":
if attr.Space == "add" || attr.Space == "del" {
InjectElementAtPath(patchEl, newDoc)
}
}
// Recursively process child elements

// Recursively handle child elements
for _, child := range patchEl.ChildElements() {
PatchElements(child, newDoc)
}
}

// InjectElementAtPath either adds or deletes elements and attributes from the target document
// based on the patch instruction.
func InjectElementAtPath(el *etree.Element, doc *etree.Document) {

// Try to find the element in the target document
match := doc.FindElement(el.GetPath())

// If no matching element found, create necessary path
if match == nil {
current := doc.Root()
parts := strings.Split(el.GetPath(), "/")
// No match found in doc, we need to create the new path

// Traverse or create the path in the target document
for i := 2; i < len(parts); i++ {
match = current.SelectElement(parts[i])
if match == nil {
match = current.CreateElement(parts[i])
}
current = match
}

// If adding, set the text content of the element
if el.Space == "add" {
match.SetText(el.Text())
}
} else {
// If element is found and is being added, set its text content
if el.Space == "add" {
match.SetText(el.Text())
}
if el.Space == "del" {
} else if el.Space == "del" {
// If element is being deleted, remove it from its parent
match.Parent().RemoveChild(match)
}
}

// Apply attribute patches
for _, attr := range el.Attr {
if attr.Space == "add" {
match.CreateAttr(attr.Key, attr.Value)
}
if attr.Space == "del" {
} else if attr.Space == "del" {
match.RemoveAttr(attr.Key)
}

}

}

0 comments on commit 780ac15

Please sign in to comment.