From 1ceb5279df4f783275ae69390eb37002acea4671 Mon Sep 17 00:00:00 2001 From: aaronchar <> Date: Sun, 5 Jun 2022 15:22:20 -0600 Subject: [PATCH 1/4] updated the `terrafrom_providers` file copy functionality to include copying go files in subdirectories well preserving the pathing during the stage where they are copied to the `providerDir` moved the `config.go` from a file that is copying during processing to a file that is generated during the processing stage, this is so we can properly import subdirectories from the `terraform_providers` directory for example the new `netconf` folder Added in the `netconf` folder, which contains a nearly identical mirror of the `junos_helper` function from `go-netconf`. With the one exception being that the type has been moved to an interface so the possibility of expanding/altering the `netconf` portion is more accessible, this changed also required a change to the generated `provider.go` file to reference the new `netconf` helper. --- .../processProviders/go_config.go | 18 +- Internal/processProviders/processProviders.go | 91 ++-- terraform_providers/netconf/common.go | 14 + terraform_providers/netconf/helper.go | 436 ++++++++++++++++++ 4 files changed, 525 insertions(+), 34 deletions(-) rename terraform_providers/config.go => Internal/processProviders/go_config.go (73%) create mode 100644 terraform_providers/netconf/common.go create mode 100644 terraform_providers/netconf/helper.go diff --git a/terraform_providers/config.go b/Internal/processProviders/go_config.go similarity index 73% rename from terraform_providers/config.go rename to Internal/processProviders/go_config.go index a14aed86..9df90db3 100644 --- a/terraform_providers/config.go +++ b/Internal/processProviders/go_config.go @@ -1,4 +1,6 @@ -// Copyright (c) 2017-2021, Juniper Networks Inc. All rights reserved. +package processProviders + +const providerConfigContent = `// Copyright (c) 2017-2021, Juniper Networks Inc. All rights reserved. // // License: Apache 2.0 // @@ -16,11 +18,11 @@ package main -import ( - gonetconf "github.com/davedotdev/go-netconf/helpers/junos_helpers" +import( + "terraform-provider-junos-%+v/netconf" ) -// Config is the configuration structure used to instantiate the GoNETCONF provider. +// Config is the configuration structure used to instantiate the Netconf provider. type Config struct { Host string Port int @@ -30,12 +32,12 @@ type Config struct { } // Client returns a new client for the provider to use -func (c *Config) Client() (*gonetconf.GoNCClient, error) { +func (c *Config) Client() (netconf.Client, error) { return newClient(c) } -func newClient(c *Config) (*gonetconf.GoNCClient, error) { +func newClient(c *Config) (netconf.Client, error) { - client, err := gonetconf.NewClient(c.Username, c.Password, c.SSHKey, c.Host, c.Port) + client, err := netconf.NewClient(c.Username, c.Password, c.SSHKey, c.Host, c.Port) return client, err -} +}` diff --git a/Internal/processProviders/processProviders.go b/Internal/processProviders/processProviders.go index a471c180..14c0bb45 100644 --- a/Internal/processProviders/processProviders.go +++ b/Internal/processProviders/processProviders.go @@ -20,14 +20,18 @@ import ( "bytes" "encoding/xml" "fmt" + "io" + "io/fs" "io/ioutil" "log" "os" "os/exec" + "path/filepath" "regexp" "strconv" "strings" s "strings" + "sync/atomic" "unicode/utf8" "github.com/Juniper/junos-terraform/Internal/cfg" @@ -284,7 +288,7 @@ func CreateProviders(jcfg cfg.Config) error { check(err) // Write to the file - _, err = fPtr.WriteString(providerFileData) + _, err = fPtr.WriteString(fmt.Sprintf(providerFileData, jcfg.ProviderName)) // List summary data fmt.Println("--------------------------------------------------------------------------------") @@ -307,30 +311,15 @@ func CreateProviders(jcfg cfg.Config) error { tpPath += "/" } } - - // Copy the files from ../terraform_providers to the `providerDir` from the config file - files, err := ioutil.ReadDir(tpPath) - if err != nil { - fmt.Println(err) - } - - fmt.Println() - PrintHeader("Copying the rest of the required Go files") - for _, f := range files { - if strings.Contains(f.Name(), ".go") { - input, err := ioutil.ReadFile(tpPath + "/" + f.Name()) - if err != nil { - fmt.Println(err) - } - - err = ioutil.WriteFile(jcfg.ProviderDir+"/"+f.Name(), input, 0644) - if err != nil { - fmt.Println("Error creating", jcfg.ProviderDir+"/"+f.Name()) - } - - fmt.Printf("Copied file: %+v to %+v\n", f.Name(), jcfg.ProviderDir) - } + // Copy the go files from ../terraform_providers to the `providerDir` from the config file + PrintHeader("Copying files") + var fileCopyCount uint32 + if err := copyDir(tpPath, jcfg.ProviderDir, ".go", jcfg.ProviderName, &fileCopyCount); err != nil { + panic(err) } + fmt.Println("------------------------------------------------------------") + fmt.Println(fmt.Sprintf("- Copied a total of %d .go files from %s to %s -", fileCopyCount, filepath.Base(tpPath), filepath.Base(jcfg.ProviderDir))) + fmt.Println("------------------------------------------------------------") PrintHeader("Creating Go Mod") err = ioutil.WriteFile(jcfg.ProviderDir+"/go.mod", []byte(fmt.Sprintf(gomodcontent, jcfg.ProviderName)), 0644) @@ -338,6 +327,11 @@ func CreateProviders(jcfg cfg.Config) error { fmt.Println("Error creating", jcfg.ProviderDir+"/go.mod") } + PrintHeader("Creating provider config") + err = ioutil.WriteFile(jcfg.ProviderDir+"/config.go", []byte(fmt.Sprintf(providerConfigContent, jcfg.ProviderName)), 0644) + if err != nil { + fmt.Println("Error creating", jcfg.ProviderDir+"/config.go") + } // No errors, so return nil. return nil } @@ -1132,14 +1126,14 @@ package main import ( - gonetconf "github.com/davedotdev/go-netconf/helpers/junos_helpers" + "terraform-provider-junos-%+v/netconf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "os" ) // ProviderConfig is to hold client information type ProviderConfig struct { - *gonetconf.GoNCClient + netconf.Client Host string } @@ -1204,3 +1198,48 @@ func Provider() *schema.Provider { ResourcesMap: map[string]*schema.Resource{ ` } + +func copyDir(src, dst, extension string, providerName string, fileCopyCount *uint32) error { + return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + if !strings.Contains(info.Name(), extension) { + return nil + } + atomic.AddUint32(fileCopyCount, 1) + } + fmt.Println(fmt.Sprintf("- Copying %s to %s", info.Name(), filepath.Base(dst))) + outpath := filepath.Join(dst, strings.TrimPrefix(path, src)) + if info.IsDir() { + os.MkdirAll(outpath, info.Mode()) + return nil // means recursive + } + if !info.Mode().IsRegular() { + switch info.Mode().Type() & os.ModeType { + case os.ModeSymlink: + link, err := os.Readlink(path) + if err != nil { + return err + } + return os.Symlink(link, outpath) + } + return nil + } + in, _ := os.Open(path) + if err != nil { + return err + } + defer in.Close() + fh, err := os.Create(outpath) + if err != nil { + return err + } + defer fh.Close() + + fh.Chmod(info.Mode()) + _, err = io.Copy(fh, in) + return err + }) +} diff --git a/terraform_providers/netconf/common.go b/terraform_providers/netconf/common.go new file mode 100644 index 00000000..49b5a1d0 --- /dev/null +++ b/terraform_providers/netconf/common.go @@ -0,0 +1,14 @@ +package netconf + +type Client interface { + Close() error + ReadGroup(applygroup string) (string, error) + UpdateRawConfig(applygroup string, netconfcall string, commit bool) (string, error) + DeleteConfig(applygroup string) (string, error) + DeleteConfigNoCommit(applygroup string) (string, error) + SendCommit() error + MarshalGroup(id string, obj interface{}) error + SendTransaction(id string, obj interface{}, commit bool) error + SendRawConfig(netconfcall string, commit bool) (string, error) + ReadRawGroup(applygroup string) (string, error) +} diff --git a/terraform_providers/netconf/helper.go b/terraform_providers/netconf/helper.go new file mode 100644 index 00000000..eab90362 --- /dev/null +++ b/terraform_providers/netconf/helper.go @@ -0,0 +1,436 @@ +package netconf + +import ( + "bufio" + "encoding/xml" + "fmt" + "io/ioutil" + "log" + "strings" + "sync" + + driver "github.com/davedotdev/go-netconf/drivers/driver" + sshdriver "github.com/davedotdev/go-netconf/drivers/ssh" + + "golang.org/x/crypto/ssh" +) + +const groupStrXML = ` +%s + +` + +const deleteStr = ` + + + + none + + + + %s + + %s + + +` + +const commitStr = `` + +const getGroupStr = ` + + %s + + +` + +const getGroupXMLStr = ` + + %s + + +` + +// GoNCClient type for storing data and wrapping functions +type GoNCClient struct { + Driver driver.Driver + Lock sync.RWMutex +} + +// Close is a functional thing to close the Driver +func (g *GoNCClient) Close() error { + g.Driver = nil + return nil +} + +// parseGroupData is a function that cleans up the returned data for generic config groups +func parseGroupData(input string) (reply string, err error) { + var cfgSlice []string + + scanner := bufio.NewScanner(strings.NewReader(input)) + scanner.Split(bufio.ScanWords) + + for scanner.Scan() { + cfgSlice = append(cfgSlice, scanner.Text()) + } + + var cfgSlice2 []string + + for _, v := range cfgSlice { + r := strings.NewReplacer("}\\n}\\n", "}", "\\n", "", "/*", "", "*/", "", "", "") + + d := r.Replace(v) + + // fmt.Println(d) + + cfgSlice2 = append(cfgSlice2, d) + } + + // Figure out the offset. Each Junos version could give us different stuff, so let's look for the group name + begin := 0 + end := 0 + + for k, v := range cfgSlice2 { + if v == "groups" { + begin = k + 4 + break + } + } + + // We don't want the very end slice due to config terminations we don't need. + end = len(cfgSlice2) - 3 + + // fmt.Printf("Begin = %v\nEnd = %v\n", begin, end) + + reply = strings.Join(cfgSlice2[begin:end], " ") + + return reply, nil +} + +// ReadGroup is a helper function +func (g *GoNCClient) ReadGroup(applygroup string) (string, error) { + g.Lock.Lock() + err := g.Driver.Dial() + + if err != nil { + log.Fatal(err) + } + + getGroupString := fmt.Sprintf(getGroupStr, applygroup) + + reply, err := g.Driver.SendRaw(getGroupString) + if err != nil { + return "", err + } + + err = g.Driver.Close() + + g.Lock.Unlock() + + if err != nil { + return "", err + } + + parsedGroupData, err := parseGroupData(reply.Data) + if err != nil { + return "", err + } + + return parsedGroupData, nil +} + +// UpdateRawConfig deletes group data and replaces it (for Update in TF) +func (g *GoNCClient) UpdateRawConfig(applygroup string, netconfcall string, commit bool) (string, error) { + + deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) + + g.Lock.Lock() + err := g.Driver.Dial() + if err != nil { + log.Fatal(err) + } + + _, err = g.Driver.SendRaw(deleteString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + groupString := fmt.Sprintf(groupStrXML, netconfcall) + + reply, err := g.Driver.SendRaw(groupString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + if commit { + _, err = g.Driver.SendRaw(commitStr) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + } + + err = g.Driver.Close() + + if err != nil { + g.Lock.Unlock() + return "", fmt.Errorf("driver close error: %+s", err) + } + + g.Lock.Unlock() + + return reply.Data, nil +} + +// DeleteConfig is a wrapper for driver.SendRaw() +func (g *GoNCClient) DeleteConfig(applygroup string) (string, error) { + + deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) + + g.Lock.Lock() + err := g.Driver.Dial() + if err != nil { + log.Fatal(err) + } + + reply, err := g.Driver.SendRaw(deleteString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + _, err = g.Driver.SendRaw(commitStr) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + output := strings.Replace(reply.Data, "\n", "", -1) + + err = g.Driver.Close() + + g.Lock.Unlock() + + if err != nil { + log.Fatal(err) + } + + return output, nil +} + +// DeleteConfigNoCommit is a wrapper for driver.SendRaw() +// Does not provide mandatory commit unlike DeleteConfig() +func (g *GoNCClient) DeleteConfigNoCommit(applygroup string) (string, error) { + + deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) + + g.Lock.Lock() + err := g.Driver.Dial() + if err != nil { + log.Fatal(err) + } + + reply, err := g.Driver.SendRaw(deleteString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + output := strings.Replace(reply.Data, "\n", "", -1) + + err = g.Driver.Close() + + if err != nil { + g.Lock.Unlock() + return "", fmt.Errorf("driver close error: %+s", err) + } + + g.Lock.Unlock() + + return output, nil +} + +// SendCommit is a wrapper for driver.SendRaw() +func (g *GoNCClient) SendCommit() error { + g.Lock.Lock() + + err := g.Driver.Dial() + + if err != nil { + g.Lock.Unlock() + return err + } + + _, err = g.Driver.SendRaw(commitStr) + if err != nil { + g.Lock.Unlock() + return err + } + + g.Lock.Unlock() + return nil +} + +// MarshalGroup accepts a struct of type X and then marshals data onto it +func (g *GoNCClient) MarshalGroup(id string, obj interface{}) error { + + reply, err := g.ReadRawGroup(id) + if err != nil { + return err + } + + err = xml.Unmarshal([]byte(reply), &obj) + if err != nil { + return err + } + return nil +} + +// SendTransaction is a method that unnmarshals the XML, creates the transaction and passes in a commit +func (g *GoNCClient) SendTransaction(id string, obj interface{}, commit bool) error { + jconfig, err := xml.Marshal(obj) + + if err != nil { + return err + } + + // UpdateRawConfig deletes old group by, re-creates it then commits. + // As far as Junos cares, it's an edit. + if id != "" { + _, err = g.UpdateRawConfig(id, string(jconfig), commit) + } else { + _, err = g.SendRawConfig(string(jconfig), commit) + } + + if err != nil { + return err + } + return nil +} + +// SendRawConfig is a wrapper for driver.SendRaw() +func (g *GoNCClient) SendRawConfig(netconfcall string, commit bool) (string, error) { + + groupString := fmt.Sprintf(groupStrXML, netconfcall) + + g.Lock.Lock() + + err := g.Driver.Dial() + + if err != nil { + log.Fatal(err) + } + + reply, err := g.Driver.SendRaw(groupString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + if commit { + _, err = g.Driver.SendRaw(commitStr) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + } + + err = g.Driver.Close() + + if err != nil { + g.Lock.Unlock() + return "", err + } + + g.Lock.Unlock() + + return reply.Data, nil +} + +// ReadRawGroup is a helper function +func (g *GoNCClient) ReadRawGroup(applygroup string) (string, error) { + g.Lock.Lock() + err := g.Driver.Dial() + + if err != nil { + log.Fatal(err) + } + + getGroupXMLString := fmt.Sprintf(getGroupXMLStr, applygroup) + + reply, err := g.Driver.SendRaw(getGroupXMLString) + if err != nil { + errInternal := g.Driver.Close() + g.Lock.Unlock() + return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + } + + err = g.Driver.Close() + + g.Lock.Unlock() + + if err != nil { + return "", err + } + + return reply.Data, nil +} + +func publicKeyFile(file string) ssh.AuthMethod { + buffer, err := ioutil.ReadFile(file) + if err != nil { + return nil + } + + key, err := ssh.ParsePrivateKey(buffer) + if err != nil { + return nil + } + return ssh.PublicKeys(key) +} + +// NewClient returns gonetconf new client driver +func NewClient(username string, password string, sshkey string, address string, port int) (Client, error) { + + // Dummy interface var ready for loading from inputs + var nconf driver.Driver + + d := driver.New(sshdriver.New()) + + nc := d.(*sshdriver.DriverSSH) + + nc.Host = address + nc.Port = port + + // SSH keys takes priority over password based + if sshkey != "" { + nc.SSHConfig = &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + publicKeyFile(sshkey), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + } else { + // Sort yourself out with SSH. Easiest to do that here. + nc.SSHConfig = &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ssh.Password(password)}, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + } + + nconf = nc + + return &GoNCClient{Driver: nconf}, nil +} From 568862ea246483136d9c168dc60c54e08829181e Mon Sep 17 00:00:00 2001 From: Aaron Chartier Date: Sun, 5 Jun 2022 15:59:41 -0600 Subject: [PATCH 2/4] removed unused variable --- Internal/processProviders/processProviders.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Internal/processProviders/processProviders.go b/Internal/processProviders/processProviders.go index 14c0bb45..9dc7f70c 100644 --- a/Internal/processProviders/processProviders.go +++ b/Internal/processProviders/processProviders.go @@ -311,11 +311,12 @@ func CreateProviders(jcfg cfg.Config) error { tpPath += "/" } } + fmt.Println(tpPath) // Copy the go files from ../terraform_providers to the `providerDir` from the config file PrintHeader("Copying files") var fileCopyCount uint32 - if err := copyDir(tpPath, jcfg.ProviderDir, ".go", jcfg.ProviderName, &fileCopyCount); err != nil { - panic(err) + if err := copyDir(tpPath, jcfg.ProviderDir, ".go", &fileCopyCount); err != nil { + return fmt.Errorf("failed to copy files from the %s direcotry: %w", tpPath, err) } fmt.Println("------------------------------------------------------------") fmt.Println(fmt.Sprintf("- Copied a total of %d .go files from %s to %s -", fileCopyCount, filepath.Base(tpPath), filepath.Base(jcfg.ProviderDir))) @@ -1199,7 +1200,7 @@ func Provider() *schema.Provider { ` } -func copyDir(src, dst, extension string, providerName string, fileCopyCount *uint32) error { +func copyDir(src, dst, extension string, fileCopyCount *uint32) error { return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { if err != nil { return err From 1fcb53b26ad7e0811d32fd977ac48ee3e800c74e Mon Sep 17 00:00:00 2001 From: aaronchar <> Date: Fri, 1 Jul 2022 15:59:11 -0600 Subject: [PATCH 3/4] chore: removed un-used print --- Internal/processProviders/processProviders.go | 1 - 1 file changed, 1 deletion(-) diff --git a/Internal/processProviders/processProviders.go b/Internal/processProviders/processProviders.go index b8add8b2..69c08673 100644 --- a/Internal/processProviders/processProviders.go +++ b/Internal/processProviders/processProviders.go @@ -311,7 +311,6 @@ func CreateProviders(jcfg cfg.Config) error { tpPath += "/" } } - fmt.Println(tpPath) // Copy the go files from ../terraform_providers to the `providerDir` from the config file PrintHeader("Copying files") var fileCopyCount uint32 From e04e78c5cc0b76ccdfd3ac8942a8c88a60f76e6a Mon Sep 17 00:00:00 2001 From: aaronchar <> Date: Fri, 8 Jul 2022 21:25:28 -0600 Subject: [PATCH 4/4] This change actually cleans up the helper overlay as well as a few other quality of life issues the main purprose of this commit is to simply remove functions from the file that are not needed for the provider by doing this it allows for a clener ingreation and makes future changes easier to manage --- Internal/processProviders/processProviders.go | 2 +- terraform_providers/netconf/common.go | 7 +- terraform_providers/netconf/helper.go | 287 ++++-------------- .../resource_junos_destroy_commit.go | 10 +- .../resource_junos_device_commit.go | 10 +- 5 files changed, 68 insertions(+), 248 deletions(-) diff --git a/Internal/processProviders/processProviders.go b/Internal/processProviders/processProviders.go index 69c08673..d3f33d08 100644 --- a/Internal/processProviders/processProviders.go +++ b/Internal/processProviders/processProviders.go @@ -415,7 +415,7 @@ import ( strUpdate = "" strDelete = ` - _, err = client.DeleteConfigNoCommit(id) + _, err = client.DeleteConfig(id,false) check(ctx, err) d.SetId("") diff --git a/terraform_providers/netconf/common.go b/terraform_providers/netconf/common.go index 49b5a1d0..0ef9ae01 100644 --- a/terraform_providers/netconf/common.go +++ b/terraform_providers/netconf/common.go @@ -2,13 +2,8 @@ package netconf type Client interface { Close() error - ReadGroup(applygroup string) (string, error) - UpdateRawConfig(applygroup string, netconfcall string, commit bool) (string, error) - DeleteConfig(applygroup string) (string, error) - DeleteConfigNoCommit(applygroup string) (string, error) + DeleteConfig(applyGroup string, commit bool) (string, error) SendCommit() error MarshalGroup(id string, obj interface{}) error SendTransaction(id string, obj interface{}, commit bool) error - SendRawConfig(netconfcall string, commit bool) (string, error) - ReadRawGroup(applygroup string) (string, error) } diff --git a/terraform_providers/netconf/helper.go b/terraform_providers/netconf/helper.go index eab90362..42328bff 100644 --- a/terraform_providers/netconf/helper.go +++ b/terraform_providers/netconf/helper.go @@ -1,11 +1,9 @@ package netconf import ( - "bufio" "encoding/xml" "fmt" "io/ioutil" - "log" "strings" "sync" @@ -37,13 +35,6 @@ const deleteStr = ` const commitStr = `` -const getGroupStr = ` - - %s - - -` - const getGroupXMLStr = ` %s @@ -63,326 +54,172 @@ func (g *GoNCClient) Close() error { return nil } -// parseGroupData is a function that cleans up the returned data for generic config groups -func parseGroupData(input string) (reply string, err error) { - var cfgSlice []string - - scanner := bufio.NewScanner(strings.NewReader(input)) - scanner.Split(bufio.ScanWords) - - for scanner.Scan() { - cfgSlice = append(cfgSlice, scanner.Text()) - } - - var cfgSlice2 []string - - for _, v := range cfgSlice { - r := strings.NewReplacer("}\\n}\\n", "}", "\\n", "", "/*", "", "*/", "", "", "") - - d := r.Replace(v) - - // fmt.Println(d) - - cfgSlice2 = append(cfgSlice2, d) - } - - // Figure out the offset. Each Junos version could give us different stuff, so let's look for the group name - begin := 0 - end := 0 - - for k, v := range cfgSlice2 { - if v == "groups" { - begin = k + 4 - break - } - } - - // We don't want the very end slice due to config terminations we don't need. - end = len(cfgSlice2) - 3 - - // fmt.Printf("Begin = %v\nEnd = %v\n", begin, end) +// updateRawConfig deletes group data and replaces it (for Update in TF) +func (g *GoNCClient) updateRawConfig(applyGroup string, netconfCall string, commit bool) (string, error) { - reply = strings.Join(cfgSlice2[begin:end], " ") - - return reply, nil -} - -// ReadGroup is a helper function -func (g *GoNCClient) ReadGroup(applygroup string) (string, error) { g.Lock.Lock() - err := g.Driver.Dial() - - if err != nil { - log.Fatal(err) - } - - getGroupString := fmt.Sprintf(getGroupStr, applygroup) - - reply, err := g.Driver.SendRaw(getGroupString) - if err != nil { - return "", err - } - - err = g.Driver.Close() - - g.Lock.Unlock() + defer g.Lock.Unlock() - if err != nil { + if err := g.Driver.Dial(); err != nil { return "", err } - parsedGroupData, err := parseGroupData(reply.Data) - if err != nil { - return "", err - } - - return parsedGroupData, nil -} - -// UpdateRawConfig deletes group data and replaces it (for Update in TF) -func (g *GoNCClient) UpdateRawConfig(applygroup string, netconfcall string, commit bool) (string, error) { - - deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) - - g.Lock.Lock() - err := g.Driver.Dial() - if err != nil { - log.Fatal(err) - } + deleteString := fmt.Sprintf(deleteStr, applyGroup, applyGroup) - _, err = g.Driver.SendRaw(deleteString) - if err != nil { + if _, err := g.Driver.SendRaw(deleteString); err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } - groupString := fmt.Sprintf(groupStrXML, netconfcall) + groupString := fmt.Sprintf(groupStrXML, netconfCall) reply, err := g.Driver.SendRaw(groupString) if err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } if commit { - _, err = g.Driver.SendRaw(commitStr) - if err != nil { + if _, err = g.Driver.SendRaw(commitStr); err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } } - err = g.Driver.Close() - - if err != nil { - g.Lock.Unlock() - return "", fmt.Errorf("driver close error: %+s", err) + if err := g.Driver.Close(); err != nil { + return "", fmt.Errorf("driver close error: %s", err) } - - g.Lock.Unlock() - return reply.Data, nil } // DeleteConfig is a wrapper for driver.SendRaw() -func (g *GoNCClient) DeleteConfig(applygroup string) (string, error) { - - deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) +func (g *GoNCClient) DeleteConfig(applyGroup string, commit bool) (string, error) { g.Lock.Lock() - err := g.Driver.Dial() - if err != nil { - log.Fatal(err) - } - - reply, err := g.Driver.SendRaw(deleteString) - if err != nil { - errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) - } - - _, err = g.Driver.SendRaw(commitStr) - if err != nil { - errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) - } - - output := strings.Replace(reply.Data, "\n", "", -1) - - err = g.Driver.Close() + defer g.Lock.Unlock() - g.Lock.Unlock() - - if err != nil { - log.Fatal(err) + if err := g.Driver.Dial(); err != nil { + return "", err } - return output, nil -} - -// DeleteConfigNoCommit is a wrapper for driver.SendRaw() -// Does not provide mandatory commit unlike DeleteConfig() -func (g *GoNCClient) DeleteConfigNoCommit(applygroup string) (string, error) { - - deleteString := fmt.Sprintf(deleteStr, applygroup, applygroup) - - g.Lock.Lock() - err := g.Driver.Dial() - if err != nil { - log.Fatal(err) - } + deleteString := fmt.Sprintf(deleteStr, applyGroup, applyGroup) reply, err := g.Driver.SendRaw(deleteString) if err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } + if commit { + if _, err = g.Driver.SendRaw(commitStr); err != nil { + errInternal := g.Driver.Close() + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) + } - output := strings.Replace(reply.Data, "\n", "", -1) - - err = g.Driver.Close() - - if err != nil { - g.Lock.Unlock() - return "", fmt.Errorf("driver close error: %+s", err) } - g.Lock.Unlock() + output := strings.Replace(reply.Data, "\n", "", -1) + if err := g.Driver.Close(); err != nil { + return "", err + } return output, nil } // SendCommit is a wrapper for driver.SendRaw() func (g *GoNCClient) SendCommit() error { g.Lock.Lock() + defer g.Lock.Unlock() - err := g.Driver.Dial() - - if err != nil { - g.Lock.Unlock() + if err := g.Driver.Dial(); err != nil { return err } - - _, err = g.Driver.SendRaw(commitStr) - if err != nil { - g.Lock.Unlock() + if _, err := g.Driver.SendRaw(commitStr); err != nil { return err } - - g.Lock.Unlock() return nil } // MarshalGroup accepts a struct of type X and then marshals data onto it func (g *GoNCClient) MarshalGroup(id string, obj interface{}) error { - reply, err := g.ReadRawGroup(id) + reply, err := g.readRawGroup(id) if err != nil { return err } - err = xml.Unmarshal([]byte(reply), &obj) - if err != nil { + if err = xml.Unmarshal([]byte(reply), &obj); err != nil { return err } return nil } -// SendTransaction is a method that unnmarshals the XML, creates the transaction and passes in a commit +// SendTransaction is a method that unmarshal the XML, creates the transaction and passes in a commit func (g *GoNCClient) SendTransaction(id string, obj interface{}, commit bool) error { - jconfig, err := xml.Marshal(obj) - + cfg, err := xml.Marshal(obj) if err != nil { return err } - - // UpdateRawConfig deletes old group by, re-creates it then commits. + // updateRawConfig deletes old group by, re-creates it then commits. // As far as Junos cares, it's an edit. if id != "" { - _, err = g.UpdateRawConfig(id, string(jconfig), commit) - } else { - _, err = g.SendRawConfig(string(jconfig), commit) + if _, err = g.updateRawConfig(id, string(cfg), commit); err != nil { + return err + } + return nil } - - if err != nil { + if _, err = g.sendRawConfig(string(cfg), commit); err != nil { return err } return nil } -// SendRawConfig is a wrapper for driver.SendRaw() -func (g *GoNCClient) SendRawConfig(netconfcall string, commit bool) (string, error) { - - groupString := fmt.Sprintf(groupStrXML, netconfcall) - +// sendRawConfig is a wrapper for driver.SendRaw() +func (g *GoNCClient) sendRawConfig(netconfCall string, commit bool) (string, error) { g.Lock.Lock() + defer g.Lock.Unlock() - err := g.Driver.Dial() - - if err != nil { - log.Fatal(err) + if err := g.Driver.Dial(); err != nil { + return "", err } + groupString := fmt.Sprintf(groupStrXML, netconfCall) reply, err := g.Driver.SendRaw(groupString) if err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } - if commit { _, err = g.Driver.SendRaw(commitStr) if err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } } - - err = g.Driver.Close() - - if err != nil { - g.Lock.Unlock() + if err = g.Driver.Close(); err != nil { return "", err } - - g.Lock.Unlock() - return reply.Data, nil } -// ReadRawGroup is a helper function -func (g *GoNCClient) ReadRawGroup(applygroup string) (string, error) { +// readRawGroup is a helper function +func (g *GoNCClient) readRawGroup(applyGroup string) (string, error) { g.Lock.Lock() - err := g.Driver.Dial() + defer g.Lock.Unlock() - if err != nil { - log.Fatal(err) + if err := g.Driver.Dial(); err != nil { + return "", err } - - getGroupXMLString := fmt.Sprintf(getGroupXMLStr, applygroup) + getGroupXMLString := fmt.Sprintf(getGroupXMLStr, applyGroup) reply, err := g.Driver.SendRaw(getGroupXMLString) if err != nil { errInternal := g.Driver.Close() - g.Lock.Unlock() - return "", fmt.Errorf("driver error: %+v, driver close error: %+s", err, errInternal) + return "", fmt.Errorf("driver error: %+v, driver close error: %s", err, errInternal) } - err = g.Driver.Close() - - g.Lock.Unlock() - - if err != nil { + if err = g.Driver.Close(); err != nil { return "", err } - return reply.Data, nil } @@ -399,8 +236,8 @@ func publicKeyFile(file string) ssh.AuthMethod { return ssh.PublicKeys(key) } -// NewClient returns gonetconf new client driver -func NewClient(username string, password string, sshkey string, address string, port int) (Client, error) { +// NewClient returns go-netconf new client driver +func NewClient(username string, password string, sshKey string, address string, port int) (Client, error) { // Dummy interface var ready for loading from inputs var nconf driver.Driver @@ -413,11 +250,11 @@ func NewClient(username string, password string, sshkey string, address string, nc.Port = port // SSH keys takes priority over password based - if sshkey != "" { + if sshKey != "" { nc.SSHConfig = &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ - publicKeyFile(sshkey), + publicKeyFile(sshKey), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } diff --git a/terraform_providers/resource_junos_destroy_commit.go b/terraform_providers/resource_junos_destroy_commit.go index 8c5eebff..abae62ab 100644 --- a/terraform_providers/resource_junos_destroy_commit.go +++ b/terraform_providers/resource_junos_destroy_commit.go @@ -53,21 +53,15 @@ func junosDestroyCommitUpdate(ctx context.Context, d *schema.ResourceData, m int func junosDestroyCommitDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - var err error - client := m.(*ProviderConfig) - err = client.SendCommit() - - if err != nil { + if err := client.SendCommit(); err != nil { return diag.FromErr(err) } - err = client.Close() - if err != nil { + if err := client.Close(); err != nil { return diag.FromErr(err) } - return nil } diff --git a/terraform_providers/resource_junos_device_commit.go b/terraform_providers/resource_junos_device_commit.go index 716e503b..de368860 100644 --- a/terraform_providers/resource_junos_device_commit.go +++ b/terraform_providers/resource_junos_device_commit.go @@ -26,24 +26,18 @@ import ( func junosCommitCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - var err error id := d.Get("resource_name").(string) client := m.(*ProviderConfig) - err = client.SendCommit() - - if err != nil { + if err := client.SendCommit(); err != nil { return diag.FromErr(err) } - d.SetId(fmt.Sprintf("%s_%s", client.Host, id)) - err = client.Close() - if err != nil { + if err := client.Close(); err != nil { return diag.FromErr(err) } - return junosCommitRead(ctx, d, m) }