From 67f9e0b6fb5f39015d0caa7d17f72ac51a6f557e Mon Sep 17 00:00:00 2001 From: lauralani Date: Sat, 25 Mar 2023 15:16:26 +0100 Subject: [PATCH] fix whitespace stuff --- cmd/classes.go | 74 +++--- cmd/constants.go | 2 +- cmd/export.go | 142 +++++------ cmd/generic.go | 10 +- cmd/import.go | 106 ++++---- cmd/ip-add.go | 136 +++++----- cmd/ip-delete.go | 102 ++++---- cmd/ip-edit.go | 36 +-- cmd/ip-show.go | 76 +++--- cmd/ip.go | 26 +- cmd/powerdns.go | 596 +++++++++++++++++++++---------------------- cmd/root.go | 94 +++---- cmd/storage.go | 212 +++++++-------- cmd/subnet-add.go | 132 +++++----- cmd/subnet-delete.go | 124 ++++----- cmd/subnet-list.go | 124 ++++----- cmd/subnet-show.go | 98 +++---- cmd/subnet.go | 26 +- main.go | 2 +- 19 files changed, 1059 insertions(+), 1059 deletions(-) diff --git a/cmd/classes.go b/cmd/classes.go index 7abd575..aa3efe9 100644 --- a/cmd/classes.go +++ b/cmd/classes.go @@ -5,32 +5,32 @@ Copyright © 2023 Laura Kalb package cmd import ( - "errors" - "net/netip" - "time" + "errors" + "net/netip" + "time" ) type Subnet struct { - Subnet netip.Prefix `json:"subnet"` - Name string `json:"name"` - Vlan string `json:"vlan"` - ChangedAt time.Time `json:"changedat,omitempty"` - ChangedBy string `json:"changedby,omitempty"` - Addresses []Address `json:"addresses"` + Subnet netip.Prefix `json:"subnet"` + Name string `json:"name"` + Vlan string `json:"vlan"` + ChangedAt time.Time `json:"changedat,omitempty"` + ChangedBy string `json:"changedby,omitempty"` + Addresses []Address `json:"addresses"` } // HasIP checks if a Subnet already contains given netip.Addr. // Returns true if the IP already is present, false otherwise. func (s Subnet) HasIP(ip netip.Addr) bool { - iscontained := false + iscontained := false - for _, element := range s.Addresses { - if element.IP.Compare(ip) == 0 { - iscontained = true - } - } + for _, element := range s.Addresses { + if element.IP.Compare(ip) == 0 { + iscontained = true + } + } - return iscontained + return iscontained } // RemoveIP removes the Address object for given ip from @@ -40,20 +40,20 @@ func (s Subnet) HasIP(ip netip.Addr) bool { // successful, or an empty Subnet and an error if // ip could not be deleted. func (s Subnet) RemoveIP(ip netip.Addr) (Subnet, error) { - var addrlist []Address + var addrlist []Address - if !s.HasIP(ip) { + if !s.HasIP(ip) { - return Subnet{}, errors.New("IP " + ip.String() + " wasn't found in subnet " + s.Subnet.String()) - } + return Subnet{}, errors.New("IP " + ip.String() + " wasn't found in subnet " + s.Subnet.String()) + } - for _, item := range s.Addresses { - if item.IP.Compare(ip) != 0 { - addrlist = append(addrlist, item) - } - } - s.Addresses = addrlist - return s, nil + for _, item := range s.Addresses { + if item.IP.Compare(ip) != 0 { + addrlist = append(addrlist, item) + } + } + s.Addresses = addrlist + return s, nil } // GetIP returns the Address object for the subnet with @@ -62,18 +62,18 @@ func (s Subnet) RemoveIP(ip netip.Addr) (Subnet, error) { // Returns the Address object and true if a corresponding // object was found, an empty Address and false otherwise. func (s Subnet) GetIP(ip netip.Addr) (Address, bool) { - for _, item := range s.Addresses { - if item.IP.Compare(ip) == 0 { - return item, true - } - } + for _, item := range s.Addresses { + if item.IP.Compare(ip) == 0 { + return item, true + } + } - return Address{}, false + return Address{}, false } type Address struct { - IP netip.Addr `json:"ip"` - FQDN string `json:"fqdn"` - ChangedAt time.Time `json:"changedat,omitempty"` - ChangedBy string `json:"changedby,omitempty"` + IP netip.Addr `json:"ip"` + FQDN string `json:"fqdn"` + ChangedAt time.Time `json:"changedat,omitempty"` + ChangedBy string `json:"changedby,omitempty"` } diff --git a/cmd/constants.go b/cmd/constants.go index f92ef79..2b8840a 100644 --- a/cmd/constants.go +++ b/cmd/constants.go @@ -5,5 +5,5 @@ Copyright © 2023 Laura Kalb package cmd const ( - ipam_version = "DEVEL" + ipam_version = "DEVEL" ) diff --git a/cmd/export.go b/cmd/export.go index e5afe6f..41cbe64 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -5,92 +5,92 @@ Copyright © 2023 Laura Kalb package cmd import ( - "encoding/json" - "fmt" - "net/netip" - "os" - "path" - "time" + "encoding/json" + "fmt" + "net/netip" + "os" + "path" + "time" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // exportCmd represents the export command var exportCmd = &cobra.Command{ - Use: "export", - Short: "Export current ipam configuration (not implemented)", - Long: `Export current ipam contents to importable data format. + Use: "export", + Short: "Export current ipam configuration (not implemented)", + Long: `Export current ipam contents to importable data format. You can either export a single subnet or all subnets.`, - Example: "ipam export\nipam export 192.168.0.0/24", - Args: cobra.RangeArgs(0, 1), - Aliases: []string{"ex"}, - Run: func(cmd *cobra.Command, args []string) { - var jsonoutput []Subnet - if len(args) == 1 { - prefix, parseerr := netip.ParsePrefix(args[0]) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + Example: "ipam export\nipam export 192.168.0.0/24", + Args: cobra.RangeArgs(0, 1), + Aliases: []string{"ex"}, + Run: func(cmd *cobra.Command, args []string) { + var jsonoutput []Subnet + if len(args) == 1 { + prefix, parseerr := netip.ParsePrefix(args[0]) + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - subnet, geterr := GetSubnet(prefix) - if geterr != nil { - fmt.Println("[ERROR]", geterr) - os.Exit(1) - } - jsonoutput = append(jsonoutput, subnet) - } else { - subnetlist := ListSubnets() - for _, net := range subnetlist { - prefix, parseerr := netip.ParsePrefix(net) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } - subnet, geterr := GetSubnet(prefix) - if geterr != nil { - fmt.Println("[ERROR]", geterr) - os.Exit(1) - } - jsonoutput = append(jsonoutput, subnet) - } - } + subnet, geterr := GetSubnet(prefix) + if geterr != nil { + fmt.Println("[ERROR]", geterr) + os.Exit(1) + } + jsonoutput = append(jsonoutput, subnet) + } else { + subnetlist := ListSubnets() + for _, net := range subnetlist { + prefix, parseerr := netip.ParsePrefix(net) + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } + subnet, geterr := GetSubnet(prefix) + if geterr != nil { + fmt.Println("[ERROR]", geterr) + os.Exit(1) + } + jsonoutput = append(jsonoutput, subnet) + } + } - //workingdir, _ := os.Getwd() - //timestamp := time.Now().Format("2006-01-02_15-04") - //exportfilename := workingdir + "/ipam_export_" + timestamp + ".json" + //workingdir, _ := os.Getwd() + //timestamp := time.Now().Format("2006-01-02_15-04") + //exportfilename := workingdir + "/ipam_export_" + timestamp + ".json" - var exportname string + var exportname string - flagpath, _ := cmd.Flags().GetString("file") - if path.IsAbs(flagpath) { - exportname = flagpath - } else { - wd, _ := os.Getwd() - exportname = path.Join(wd, flagpath) - } + flagpath, _ := cmd.Flags().GetString("file") + if path.IsAbs(flagpath) { + exportname = flagpath + } else { + wd, _ := os.Getwd() + exportname = path.Join(wd, flagpath) + } - data, _ := json.MarshalIndent(jsonoutput, "", " ") + data, _ := json.MarshalIndent(jsonoutput, "", " ") - file, fileerr := os.Create(exportname) - if fileerr != nil { - fmt.Println("[ERROR]", fileerr) - os.Exit(1) - } - defer file.Close() + file, fileerr := os.Create(exportname) + if fileerr != nil { + fmt.Println("[ERROR]", fileerr) + os.Exit(1) + } + defer file.Close() - _, writeerr := file.Write(data) - if writeerr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } - fmt.Printf("[INFO] Data was exported to file %v\n", exportname) - }, + _, writeerr := file.Write(data) + if writeerr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } + fmt.Printf("[INFO] Data was exported to file %v\n", exportname) + }, } func init() { - rootCmd.AddCommand(exportCmd) + rootCmd.AddCommand(exportCmd) - timestamp := time.Now().Format("2006-01-02_15-04") - exportCmd.Flags().StringP("file", "f", "./ipam_export_"+timestamp+".json", "File name for exported data.\nCan be both absolute or relative path.") + timestamp := time.Now().Format("2006-01-02_15-04") + exportCmd.Flags().StringP("file", "f", "./ipam_export_"+timestamp+".json", "File name for exported data.\nCan be both absolute or relative path.") } diff --git a/cmd/generic.go b/cmd/generic.go index a07f7e2..00926d0 100644 --- a/cmd/generic.go +++ b/cmd/generic.go @@ -1,9 +1,9 @@ package cmd func reverse(elements []string) []string { - for i := 0; i < len(elements)/2; i++ { - j := len(elements) - i - 1 - elements[i], elements[j] = elements[j], elements[i] - } - return elements + for i := 0; i < len(elements)/2; i++ { + j := len(elements) - i - 1 + elements[i], elements[j] = elements[j], elements[i] + } + return elements } diff --git a/cmd/import.go b/cmd/import.go index d4b63a2..39eb3c7 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -5,72 +5,72 @@ Copyright © 2023 Laura Kalb package cmd import ( - "encoding/json" - "fmt" - "os" - "path" - "time" + "encoding/json" + "fmt" + "os" + "path" + "time" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) var importCmd = &cobra.Command{ - Use: "import", - Short: "Import ipam configuration (not implemented)", - Long: `Import subnets to ipam.`, - Example: "ipam import --file import.json", - Args: cobra.NoArgs, - Aliases: []string{"im"}, - Run: func(cmd *cobra.Command, args []string) { - var importname string - var subnets []Subnet + Use: "import", + Short: "Import ipam configuration (not implemented)", + Long: `Import subnets to ipam.`, + Example: "ipam import --file import.json", + Args: cobra.NoArgs, + Aliases: []string{"im"}, + Run: func(cmd *cobra.Command, args []string) { + var importname string + var subnets []Subnet - flagpath, _ := cmd.Flags().GetString("file") - if path.IsAbs(flagpath) { - importname = flagpath - } else { - wd, _ := os.Getwd() - importname = path.Join(wd, flagpath) - } + flagpath, _ := cmd.Flags().GetString("file") + if path.IsAbs(flagpath) { + importname = flagpath + } else { + wd, _ := os.Getwd() + importname = path.Join(wd, flagpath) + } - file, readerr := os.ReadFile(importname) - if readerr != nil { - fmt.Printf("[ERROR] Can't read file %v\n", importname) - fmt.Println(readerr) - } + file, readerr := os.ReadFile(importname) + if readerr != nil { + fmt.Printf("[ERROR] Can't read file %v\n", importname) + fmt.Println(readerr) + } - marsherr := json.Unmarshal(file, &subnets) - if marsherr != nil { - fmt.Printf("[ERROR] Invalid format for file %v\n", importname) - fmt.Println(marsherr) - } + marsherr := json.Unmarshal(file, &subnets) + if marsherr != nil { + fmt.Printf("[ERROR] Invalid format for file %v\n", importname) + fmt.Println(marsherr) + } - for _, subnet := range subnets { - fmt.Printf("[INFO] Start import of %v\n", subnet.Subnet.String()) - subnet.ChangedBy = "ipam import" - subnet.ChangedAt = time.Now() + for _, subnet := range subnets { + fmt.Printf("[INFO] Start import of %v\n", subnet.Subnet.String()) + subnet.ChangedBy = "ipam import" + subnet.ChangedAt = time.Now() - for _, addr := range subnet.Addresses { - addr.ChangedBy = "ipam import" - addr.ChangedAt = time.Now() - if addr.FQDN != "" { - AddDNSFqdn(addr.FQDN, addr.IP) - } - } + for _, addr := range subnet.Addresses { + addr.ChangedBy = "ipam import" + addr.ChangedAt = time.Now() + if addr.FQDN != "" { + AddDNSFqdn(addr.FQDN, addr.IP) + } + } - suberr := subnet.WriteSubnet() - if suberr != nil { - fmt.Printf("[ERROR] Can't write subnet to file %v\n", subnet.Subnet.String()) - fmt.Println(suberr) - } - fmt.Printf("[INFO] Imported subnet %v successfully\n", subnet.Subnet.String()) + suberr := subnet.WriteSubnet() + if suberr != nil { + fmt.Printf("[ERROR] Can't write subnet to file %v\n", subnet.Subnet.String()) + fmt.Println(suberr) + } + fmt.Printf("[INFO] Imported subnet %v successfully\n", subnet.Subnet.String()) - } - }, + } + }, } func init() { - rootCmd.AddCommand(importCmd) + rootCmd.AddCommand(importCmd) - importCmd.Flags().StringP("file", "f", "import.json", "File to use for import operation") + importCmd.Flags().StringP("file", "f", "import.json", "File to use for import operation") } diff --git a/cmd/ip-add.go b/cmd/ip-add.go index 55feb6f..38f8c54 100644 --- a/cmd/ip-add.go +++ b/cmd/ip-add.go @@ -5,92 +5,92 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" - "os/user" - "time" + "fmt" + "net/netip" + "os" + "os/user" + "time" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) var ipaddCmd = &cobra.Command{ - Use: "add ipaddress [hostname]", - Short: "Add new IP address", - Long: `Add new IP address`, - Aliases: []string{"a"}, - Args: cobra.RangeArgs(1, 2), - Run: func(cmd *cobra.Command, args []string) { - var ipaddress, hostname string + Use: "add ipaddress [hostname]", + Short: "Add new IP address", + Long: `Add new IP address`, + Aliases: []string{"a"}, + Args: cobra.RangeArgs(1, 2), + Run: func(cmd *cobra.Command, args []string) { + var ipaddress, hostname string - if len(args) == 1 { - ipaddress = args[0] - hostname = "" - } else { - ipaddress = args[0] - hostname = args[1] - } + if len(args) == 1 { + ipaddress = args[0] + hostname = "" + } else { + ipaddress = args[0] + hostname = args[1] + } - ip, parseerr := netip.ParseAddr(ipaddress) + ip, parseerr := netip.ParseAddr(ipaddress) - // Exit if parsed value is no valid IP - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + // Exit if parsed value is no valid IP + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - // Exit if parsed value is an IPv6 Address - // TODO: Implement IPv6 support - if !ip.Is4() { - fmt.Printf("[ERROR] IPv6 is not yet supported!\n") - os.Exit(1) - } + // Exit if parsed value is an IPv6 Address + // TODO: Implement IPv6 support + if !ip.Is4() { + fmt.Printf("[ERROR] IPv6 is not yet supported!\n") + os.Exit(1) + } - subnet, subnetexists := FindBestSubnet(ip) + subnet, subnetexists := FindBestSubnet(ip) - if !subnetexists { - fmt.Printf("[ERROR] Found no suitable subnet for IP %v\n", ipaddress) - fmt.Printf("[ERROR] Maybe you need to add it first?\n") - os.Exit(1) - } + if !subnetexists { + fmt.Printf("[ERROR] Found no suitable subnet for IP %v\n", ipaddress) + fmt.Printf("[ERROR] Maybe you need to add it first?\n") + os.Exit(1) + } - if subnet.HasIP(ip) { - fmt.Printf("[ERROR] IP %v already exists in subnet %v\n", ip.String(), subnet.Subnet.String()) - os.Exit(1) - } + if subnet.HasIP(ip) { + fmt.Printf("[ERROR] IP %v already exists in subnet %v\n", ip.String(), subnet.Subnet.String()) + os.Exit(1) + } - currentuser, _ := user.Current() - subnet.Addresses = append(subnet.Addresses, Address{ip, hostname, time.Now(), currentuser.Username}) + currentuser, _ := user.Current() + subnet.Addresses = append(subnet.Addresses, Address{ip, hostname, time.Now(), currentuser.Username}) - writeerr := subnet.WriteSubnet() - if writeerr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } + writeerr := subnet.WriteSubnet() + if writeerr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } - if hostname == "" { - fmt.Printf("added ip:\nip: %v\n", ipaddress) - } else { - fmt.Printf("added ip:\nip: %v\nhostname: %v\n", ipaddress, hostname) - dnserr := AddDNSFqdn(hostname, ip) - if dnserr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } - } - }, + if hostname == "" { + fmt.Printf("added ip:\nip: %v\n", ipaddress) + } else { + fmt.Printf("added ip:\nip: %v\nhostname: %v\n", ipaddress, hostname) + dnserr := AddDNSFqdn(hostname, ip) + if dnserr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } + } + }, } func init() { - ipCmd.AddCommand(ipaddCmd) + ipCmd.AddCommand(ipaddCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // addCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // addCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/ip-delete.go b/cmd/ip-delete.go index 02af04f..6eaea9d 100644 --- a/cmd/ip-delete.go +++ b/cmd/ip-delete.go @@ -4,72 +4,72 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" + "fmt" + "net/netip" + "os" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // deleteCmd represents the delete command var ipdeleteCmd = &cobra.Command{ - Use: "delete ipaddress", - Short: "Delete an IP address", - Long: `Delete an IP address`, - Aliases: []string{"d"}, - Args: cobra.ExactArgs(1), - Example: "ipam ip delete 192.168.0.1", - Run: func(cmd *cobra.Command, args []string) { - ip, parseerr := netip.ParseAddr(args[0]) + Use: "delete ipaddress", + Short: "Delete an IP address", + Long: `Delete an IP address`, + Aliases: []string{"d"}, + Args: cobra.ExactArgs(1), + Example: "ipam ip delete 192.168.0.1", + Run: func(cmd *cobra.Command, args []string) { + ip, parseerr := netip.ParseAddr(args[0]) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - subnet, subnetexists := FindBestSubnet(ip) - if !subnetexists { - fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) - os.Exit(1) - } + subnet, subnetexists := FindBestSubnet(ip) + if !subnetexists { + fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) + os.Exit(1) + } - address, _ := subnet.GetIP(ip) + address, _ := subnet.GetIP(ip) - subnet, removeerr := subnet.RemoveIP(ip) - if removeerr != nil { - fmt.Println("[ERROR]", removeerr) - os.Exit(1) - } + subnet, removeerr := subnet.RemoveIP(ip) + if removeerr != nil { + fmt.Println("[ERROR]", removeerr) + os.Exit(1) + } - writeerr := subnet.WriteSubnet() - if writeerr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } + writeerr := subnet.WriteSubnet() + if writeerr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } - if address.FQDN == "" { - fmt.Printf("deleted ip %v\n", address.IP.String()) - } else { - fmt.Printf("deleted ip %v (%v)\n", address.IP.String(), address.FQDN) - dnserr := DeleteDNSFqdn(address.FQDN, address.IP) - if dnserr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } - } - }, + if address.FQDN == "" { + fmt.Printf("deleted ip %v\n", address.IP.String()) + } else { + fmt.Printf("deleted ip %v (%v)\n", address.IP.String(), address.FQDN) + dnserr := DeleteDNSFqdn(address.FQDN, address.IP) + if dnserr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } + } + }, } func init() { - ipCmd.AddCommand(ipdeleteCmd) + ipCmd.AddCommand(ipdeleteCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/ip-edit.go b/cmd/ip-edit.go index 8aa07a0..00c5204 100644 --- a/cmd/ip-edit.go +++ b/cmd/ip-edit.go @@ -4,32 +4,32 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" + "fmt" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) var ipeditCmd = &cobra.Command{ - Use: "edit", - Short: "Edit an IP address", - Long: `Edit an IP address`, - Aliases: []string{"e"}, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("not implemented yet; please delete and readd") - }, + Use: "edit", + Short: "Edit an IP address", + Long: `Edit an IP address`, + Aliases: []string{"e"}, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("not implemented yet; please delete and readd") + }, } func init() { - ipCmd.AddCommand(ipeditCmd) + ipCmd.AddCommand(ipeditCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // editCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // editCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // editCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // editCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/ip-show.go b/cmd/ip-show.go index 026c6eb..d6c7a1b 100644 --- a/cmd/ip-show.go +++ b/cmd/ip-show.go @@ -4,57 +4,57 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" + "fmt" + "net/netip" + "os" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // showCmd represents the show command var ipshowCmd = &cobra.Command{ - Use: "show", - Short: "Show IP and associated name", - Long: `Show IP and associated name`, - Aliases: []string{"s"}, - Args: cobra.ExactArgs(1), - Example: "ipam ip show 192.168.0.1", - Run: func(cmd *cobra.Command, args []string) { - ip, parseerr := netip.ParseAddr(args[0]) + Use: "show", + Short: "Show IP and associated name", + Long: `Show IP and associated name`, + Aliases: []string{"s"}, + Args: cobra.ExactArgs(1), + Example: "ipam ip show 192.168.0.1", + Run: func(cmd *cobra.Command, args []string) { + ip, parseerr := netip.ParseAddr(args[0]) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - subnet, subnetexists := FindBestSubnet(ip) - if !subnetexists { - fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) - os.Exit(1) - } + subnet, subnetexists := FindBestSubnet(ip) + if !subnetexists { + fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) + os.Exit(1) + } - addr, addrexists := subnet.GetIP(ip) - if !addrexists { - fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) - os.Exit(1) - } + addr, addrexists := subnet.GetIP(ip) + if !addrexists { + fmt.Printf("[ERROR] Couldn't find IP %v\n", ip.String()) + os.Exit(1) + } - fmt.Printf("IP: %v\n", ip.String()) - fmt.Printf("FQDN: %v\n", addr.FQDN) - fmt.Printf("Subnet: %v (%v)\n", subnet.Subnet.String(), subnet.Name) - }, + fmt.Printf("IP: %v\n", ip.String()) + fmt.Printf("FQDN: %v\n", addr.FQDN) + fmt.Printf("Subnet: %v (%v)\n", subnet.Subnet.String(), subnet.Name) + }, } func init() { - ipCmd.AddCommand(ipshowCmd) + ipCmd.AddCommand(ipshowCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // showCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // showCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // showCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // showCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/ip.go b/cmd/ip.go index 8df3e80..88112cc 100644 --- a/cmd/ip.go +++ b/cmd/ip.go @@ -5,27 +5,27 @@ Copyright © 2023 Laura Kalb package cmd import ( - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // ipCmd represents the ip command var ipCmd = &cobra.Command{ - Use: "ip", - Short: "manage ip addresses", - Long: `Add, delete, edit and show IP addresses`, - Aliases: []string{"i"}, + Use: "ip", + Short: "manage ip addresses", + Long: `Add, delete, edit and show IP addresses`, + Aliases: []string{"i"}, } func init() { - rootCmd.AddCommand(ipCmd) + rootCmd.AddCommand(ipCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // ipCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // ipCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // ipCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // ipCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/powerdns.go b/cmd/powerdns.go index 365a754..c6b259e 100644 --- a/cmd/powerdns.go +++ b/cmd/powerdns.go @@ -5,32 +5,32 @@ Copyright © 2023 Laura Kalb package cmd import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/netip" - "strings" + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/netip" + "strings" - "github.com/spf13/viper" + "github.com/spf13/viper" ) type DNSZone struct { - ID string `json:"id"` - Name string `json:"name"` - Kind string `json:"kind"` - RRsets []DNSRecordSet `json:"rrsets"` - Metadata map[string]string `json:"metadata"` - DNSSEC bool `json:"dnssec"` - NSEC3Param string `json:"nsec3param,omitempty"` - Account string `json:"account,omitempty"` - Serial int `json:"serial"` + ID string `json:"id"` + Name string `json:"name"` + Kind string `json:"kind"` + RRsets []DNSRecordSet `json:"rrsets"` + Metadata map[string]string `json:"metadata"` + DNSSEC bool `json:"dnssec"` + NSEC3Param string `json:"nsec3param,omitempty"` + Account string `json:"account,omitempty"` + Serial int `json:"serial"` } type Patch struct { - Rrsets []DNSRecordSet `json:"rrsets"` + Rrsets []DNSRecordSet `json:"rrsets"` } // Checks if a given Record already exists in the DNSRecordSet list. @@ -38,106 +38,106 @@ type Patch struct { // Returns the DNSRecordSet and true if record exists, empty // DNSRecordSet and false if not. func (z DNSZone) GetRecord(fqdn string, rtype string, rcontent string) (DNSRecordSet, bool) { - if !strings.HasSuffix(fqdn, ".") { - fqdn = fqdn + "." - } - if (rtype == "PTR") && !strings.HasSuffix(rcontent, ".") { - rcontent = rcontent + "." - } - for _, recordset := range z.RRsets { - if recordset.Name == fqdn && recordset.Type == rtype { - for _, record := range recordset.Records { - if record.Content == rcontent { - return recordset, true - } - } - } - } - return DNSRecordSet{}, false + if !strings.HasSuffix(fqdn, ".") { + fqdn = fqdn + "." + } + if (rtype == "PTR") && !strings.HasSuffix(rcontent, ".") { + rcontent = rcontent + "." + } + for _, recordset := range z.RRsets { + if recordset.Name == fqdn && recordset.Type == rtype { + for _, record := range recordset.Records { + if record.Content == rcontent { + return recordset, true + } + } + } + } + return DNSRecordSet{}, false } // Sends a PATCH API request for DNSZone z. Returns error or nil // // Example args for "test.example.com IN A 127.0.0.1" // -// z.Name = "example.com." -// record = "test" -// value = "127.0.0.1" -// recordtype = "A" -// changetype = "REPLACE" +// z.Name = "example.com." +// record = "test" +// value = "127.0.0.1" +// recordtype = "A" +// changetype = "REPLACE" func (z DNSZone) SendPATCH(record string, value string, recordtype string, changetype string) error { - pdnsendpoint := viper.GetString("powerdnsendpoint") - pdnsapikey := viper.GetString("powerdnsapikey") - debug, _ := rootCmd.Flags().GetBool("debug") + pdnsendpoint := viper.GetString("powerdnsendpoint") + pdnsapikey := viper.GetString("powerdnsapikey") + debug, _ := rootCmd.Flags().GetBool("debug") - if !viper.GetBool("powerdnsenabled") { - return nil - } + if !viper.GetBool("powerdnsenabled") { + return nil + } - url := pdnsendpoint + "/api/v1/servers/localhost/zones/" + z.Name - if debug { - fmt.Println("[DEBUG] PowerDNS URL: " + url) - } + url := pdnsendpoint + "/api/v1/servers/localhost/zones/" + z.Name + if debug { + fmt.Println("[DEBUG] PowerDNS URL: " + url) + } - rset := DNSRecordSet{} - rset.Changetype = changetype - rset.Name = strings.Join([]string{record, z.Name}, ".") - rset.TTL = 3600 - rset.Type = recordtype - rec := DNSRecord{} - if recordtype == "PTR" { - rec.Content = value + "." - } else { - rec.Content = value - } - rset.Records = append(rset.Records, rec) + rset := DNSRecordSet{} + rset.Changetype = changetype + rset.Name = strings.Join([]string{record, z.Name}, ".") + rset.TTL = 3600 + rset.Type = recordtype + rec := DNSRecord{} + if recordtype == "PTR" { + rec.Content = value + "." + } else { + rec.Content = value + } + rset.Records = append(rset.Records, rec) - patch := Patch{} - patch.Rrsets = append(patch.Rrsets, rset) + patch := Patch{} + patch.Rrsets = append(patch.Rrsets, rset) - payload, marsherr := json.Marshal(patch) - if marsherr != nil { - return marsherr - } + payload, marsherr := json.Marshal(patch) + if marsherr != nil { + return marsherr + } - req, reqerr := http.NewRequest("PATCH", url, bytes.NewBuffer(payload)) - if reqerr != nil { - return reqerr - } + req, reqerr := http.NewRequest("PATCH", url, bytes.NewBuffer(payload)) + if reqerr != nil { + return reqerr + } - req.Header.Add("X-API-Key", pdnsapikey) - req.Header.Add("Content-Type", "application/json") + req.Header.Add("X-API-Key", pdnsapikey) + req.Header.Add("Content-Type", "application/json") - client := &http.Client{} - resp, resperr := client.Do(req) - if resperr != nil { - return resperr - } + client := &http.Client{} + resp, resperr := client.Do(req) + if resperr != nil { + return resperr + } - if resp.StatusCode != 204 { - defer resp.Body.Close() + if resp.StatusCode != 204 { + defer resp.Body.Close() - body, readerr := io.ReadAll(resp.Body) - if readerr != nil { - fmt.Println(readerr) - } - return errors.New("HTTP Error: " + resp.Status + "\n" + string(body)) - } - return nil + body, readerr := io.ReadAll(resp.Body) + if readerr != nil { + fmt.Println(readerr) + } + return errors.New("HTTP Error: " + resp.Status + "\n" + string(body)) + } + return nil } type DNSRecordSet struct { - Name string `json:"name"` - Type string `json:"type"` - TTL int `json:"ttl"` - Records []DNSRecord `json:"records"` - Changetype string `json:"changetype,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + TTL int `json:"ttl"` + Records []DNSRecord `json:"records"` + Changetype string `json:"changetype,omitempty"` } type DNSRecord struct { - Content string `json:"content"` - Disabled bool `json:"disabled,omitempty"` - SetPTR bool `json:"set-ptr,omitempty"` + Content string `json:"content"` + Disabled bool `json:"disabled,omitempty"` + SetPTR bool `json:"set-ptr,omitempty"` } // GetDNSZone retrieves the corresponding DNSZone for string zone @@ -146,45 +146,45 @@ type DNSRecord struct { // Returns the DNSZone and nil if successful, empty DNSZone and an // error otherwise func GetDNSZone(zone string) (DNSZone, error) { - if !strings.HasSuffix(zone, ".") { - zone = zone + "." - } - pdnsendpoint := viper.GetString("powerdnsendpoint") - pdnsapikey := viper.GetString("powerdnsapikey") + if !strings.HasSuffix(zone, ".") { + zone = zone + "." + } + pdnsendpoint := viper.GetString("powerdnsendpoint") + pdnsapikey := viper.GetString("powerdnsapikey") - url := pdnsendpoint + "/api/v1/servers/localhost/zones/" + zone + url := pdnsendpoint + "/api/v1/servers/localhost/zones/" + zone - req, reqerr := http.NewRequest("GET", url, nil) - if reqerr != nil { - fmt.Println(reqerr) - return DNSZone{}, reqerr - } + req, reqerr := http.NewRequest("GET", url, nil) + if reqerr != nil { + fmt.Println(reqerr) + return DNSZone{}, reqerr + } - req.Header.Add("X-API-Key", pdnsapikey) - req.Header.Add("Accept", "application/json") + req.Header.Add("X-API-Key", pdnsapikey) + req.Header.Add("Accept", "application/json") - client := &http.Client{} - resp, resperr := client.Do(req) - if resperr != nil { - fmt.Println(resperr) - return DNSZone{}, resperr - } - defer resp.Body.Close() + client := &http.Client{} + resp, resperr := client.Do(req) + if resperr != nil { + fmt.Println(resperr) + return DNSZone{}, resperr + } + defer resp.Body.Close() - body, readerr := io.ReadAll(resp.Body) - if readerr != nil { - fmt.Println(readerr) - return DNSZone{}, readerr - } + body, readerr := io.ReadAll(resp.Body) + if readerr != nil { + fmt.Println(readerr) + return DNSZone{}, readerr + } - var zoneobj DNSZone - marsherr := json.Unmarshal(body, &zoneobj) - if marsherr != nil { - fmt.Println(marsherr) - return DNSZone{}, marsherr - } + var zoneobj DNSZone + marsherr := json.Unmarshal(body, &zoneobj) + if marsherr != nil { + fmt.Println(marsherr) + return DNSZone{}, marsherr + } - return zoneobj, nil + return zoneobj, nil } // GetBestDNSZone requests a list of all zones from PowerDNS @@ -193,70 +193,70 @@ func GetDNSZone(zone string) (DNSZone, error) { // Returns the found DNSZone and nil if a suitable zone was // found, an empty DNSZone object and an error if not. func GetBestDNSZone(fqdn string) (DNSZone, error) { - pdnsendpoint := viper.GetString("powerdnsendpoint") - pdnsapikey := viper.GetString("powerdnsapikey") - fqdn = fqdn + "." + pdnsendpoint := viper.GetString("powerdnsendpoint") + pdnsapikey := viper.GetString("powerdnsapikey") + fqdn = fqdn + "." - if !viper.GetBool("powerdnsenabled") { - return DNSZone{}, errors.New("PowerDNS integration not enabled") - } + if !viper.GetBool("powerdnsenabled") { + return DNSZone{}, errors.New("PowerDNS integration not enabled") + } - url := pdnsendpoint + "/api/v1/servers/localhost/zones" + url := pdnsendpoint + "/api/v1/servers/localhost/zones" - req, reqerr := http.NewRequest("GET", url, nil) - if reqerr != nil { - fmt.Println(reqerr) - return DNSZone{}, reqerr - } + req, reqerr := http.NewRequest("GET", url, nil) + if reqerr != nil { + fmt.Println(reqerr) + return DNSZone{}, reqerr + } - req.Header.Add("X-API-Key", pdnsapikey) + req.Header.Add("X-API-Key", pdnsapikey) - client := &http.Client{} - resp, resperr := client.Do(req) - if resperr != nil { - fmt.Println(resperr) - return DNSZone{}, resperr - } - defer resp.Body.Close() + client := &http.Client{} + resp, resperr := client.Do(req) + if resperr != nil { + fmt.Println(resperr) + return DNSZone{}, resperr + } + defer resp.Body.Close() - body, readerr := io.ReadAll(resp.Body) - if readerr != nil { - fmt.Println(readerr) - return DNSZone{}, readerr - } + body, readerr := io.ReadAll(resp.Body) + if readerr != nil { + fmt.Println(readerr) + return DNSZone{}, readerr + } - var zones []DNSZone - marsherr := json.Unmarshal(body, &zones) - if marsherr != nil { - fmt.Println(marsherr) - return DNSZone{}, marsherr - } + var zones []DNSZone + marsherr := json.Unmarshal(body, &zones) + if marsherr != nil { + fmt.Println(marsherr) + return DNSZone{}, marsherr + } - var bestmatch DNSZone - var matchfound bool = false + var bestmatch DNSZone + var matchfound bool = false - for _, zone := range zones { - if strings.HasSuffix(fqdn, zone.Name) { - if !matchfound { - matchfound = true - bestmatch = zone - } - if matchfound && len(zone.Name) > len(bestmatch.Name) { - bestmatch = zone - } - } - } + for _, zone := range zones { + if strings.HasSuffix(fqdn, zone.Name) { + if !matchfound { + matchfound = true + bestmatch = zone + } + if matchfound && len(zone.Name) > len(bestmatch.Name) { + bestmatch = zone + } + } + } - if !matchfound { - return DNSZone{}, errors.New("No suitable zone found for " + fqdn) - } + if !matchfound { + return DNSZone{}, errors.New("No suitable zone found for " + fqdn) + } - zone, geterr := GetDNSZone(bestmatch.ID) - if geterr != nil { - return DNSZone{}, geterr - } + zone, geterr := GetDNSZone(bestmatch.ID) + if geterr != nil { + return DNSZone{}, geterr + } - return zone, nil + return zone, nil } // AddDNSfqdn tries to create forward and reverse lookup records @@ -265,74 +265,74 @@ func GetBestDNSZone(fqdn string) (DNSZone, error) { // // Returns nil on success, error otherwise func AddDNSFqdn(fqdn string, addr netip.Addr) error { - debug, _ := rootCmd.Flags().GetBool("debug") - if !viper.GetBool("powerdnsenabled") { - if debug { - fmt.Println("[INFO] PowerDNS integration disabled, skipping DNS operations.") - } - return nil - } + debug, _ := rootCmd.Flags().GetBool("debug") + if !viper.GetBool("powerdnsenabled") { + if debug { + fmt.Println("[INFO] PowerDNS integration disabled, skipping DNS operations.") + } + return nil + } - var recordtype string - if addr.Is4() { - recordtype = "A" - } else if addr.Is6() { - recordtype = "AAAA" - } else { - return errors.New(addr.String() + " is not a valid IP address") - } + var recordtype string + if addr.Is4() { + recordtype = "A" + } else if addr.Is6() { + recordtype = "AAAA" + } else { + return errors.New(addr.String() + " is not a valid IP address") + } - fzone, fzoneerr := GetBestDNSZone(fqdn) - if fzoneerr != nil { - fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS op\n", fqdn) - } else { + fzone, fzoneerr := GetBestDNSZone(fqdn) + if fzoneerr != nil { + fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS op\n", fqdn) + } else { - _, frecordexists := fzone.GetRecord(fqdn, recordtype, addr.String()) + _, frecordexists := fzone.GetRecord(fqdn, recordtype, addr.String()) - if frecordexists { - fmt.Printf("[DNS] DNS Record for %v already exists, no need to change DNS.\n", fqdn) - } else { - fpatcherr := fzone.SendPATCH(strings.Replace(fqdn+".", "."+fzone.Name, "", 1), addr.String(), recordtype, "REPLACE") - if fpatcherr != nil { - return fpatcherr - } - fmt.Printf("[DNS] + %v IN %v %v\n", fqdn, recordtype, addr.String()) - } - } + if frecordexists { + fmt.Printf("[DNS] DNS Record for %v already exists, no need to change DNS.\n", fqdn) + } else { + fpatcherr := fzone.SendPATCH(strings.Replace(fqdn+".", "."+fzone.Name, "", 1), addr.String(), recordtype, "REPLACE") + if fpatcherr != nil { + return fpatcherr + } + fmt.Printf("[DNS] + %v IN %v %v\n", fqdn, recordtype, addr.String()) + } + } - baseip := addr.StringExpanded() - var rfqdn string - if addr.Is4() { - a := strings.Split(baseip, ".") - b := reverse(a) - rfqdn = strings.Join(b, ".") + ".in-addr.arpa" - } else if addr.Is6() { - a := strings.Replace(baseip, ":", "", -1) - b := strings.Split(a, "") - c := reverse(b) - rfqdn = strings.Join(c, ".") + ".ip6.arpa" - } + baseip := addr.StringExpanded() + var rfqdn string + if addr.Is4() { + a := strings.Split(baseip, ".") + b := reverse(a) + rfqdn = strings.Join(b, ".") + ".in-addr.arpa" + } else if addr.Is6() { + a := strings.Replace(baseip, ":", "", -1) + b := strings.Split(a, "") + c := reverse(b) + rfqdn = strings.Join(c, ".") + ".ip6.arpa" + } - rzone, rzoneerr := GetBestDNSZone(rfqdn) - if rzoneerr != nil { - fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS op\n", rfqdn) - } else { + rzone, rzoneerr := GetBestDNSZone(rfqdn) + if rzoneerr != nil { + fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS op\n", rfqdn) + } else { - _, rrecordexists := rzone.GetRecord(rfqdn, "PTR", fqdn) - rhost := strings.Replace(rfqdn+".", "."+rzone.Name, "", 1) + _, rrecordexists := rzone.GetRecord(rfqdn, "PTR", fqdn) + rhost := strings.Replace(rfqdn+".", "."+rzone.Name, "", 1) - if rrecordexists { - fmt.Printf("[DNS] Reverse DNS Record for %v already exists, no need to change DNS.\n", addr.String()) - } else { - rpatcherr := rzone.SendPATCH(rhost, fqdn, "PTR", "REPLACE") - if rpatcherr != nil { - return rpatcherr - } - fmt.Printf("[DNS] + %v IN %v %v\n", rfqdn, "PTR", fqdn) - } - } + if rrecordexists { + fmt.Printf("[DNS] Reverse DNS Record for %v already exists, no need to change DNS.\n", addr.String()) + } else { + rpatcherr := rzone.SendPATCH(rhost, fqdn, "PTR", "REPLACE") + if rpatcherr != nil { + return rpatcherr + } + fmt.Printf("[DNS] + %v IN %v %v\n", rfqdn, "PTR", fqdn) + } + } - return nil + return nil } // DeleteDNSFqdn tries to delete the corresponding record for @@ -340,70 +340,70 @@ func AddDNSFqdn(fqdn string, addr netip.Addr) error { // // Returns nil on success, error otherwise func DeleteDNSFqdn(fqdn string, addr netip.Addr) error { - debug, _ := rootCmd.Flags().GetBool("debug") - if !viper.GetBool("powerdnsenabled") { - if debug { - fmt.Println("[INFO] PowerDNS integration disabled, skipping DNS operations.") - } - return nil - } + debug, _ := rootCmd.Flags().GetBool("debug") + if !viper.GetBool("powerdnsenabled") { + if debug { + fmt.Println("[INFO] PowerDNS integration disabled, skipping DNS operations.") + } + return nil + } - var recordtype string - if addr.Is4() { - recordtype = "A" - } else if addr.Is6() { - recordtype = "AAAA" - } else { - return errors.New(addr.String() + " is not a valid IP address") - } + var recordtype string + if addr.Is4() { + recordtype = "A" + } else if addr.Is6() { + recordtype = "AAAA" + } else { + return errors.New(addr.String() + " is not a valid IP address") + } - fzone, fzoneerr := GetBestDNSZone(fqdn) - if fzoneerr != nil { - fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS delete op\n", fqdn) - } else { - _, frecordexists := fzone.GetRecord(fqdn, recordtype, addr.String()) + fzone, fzoneerr := GetBestDNSZone(fqdn) + if fzoneerr != nil { + fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS delete op\n", fqdn) + } else { + _, frecordexists := fzone.GetRecord(fqdn, recordtype, addr.String()) - if !frecordexists { - fmt.Printf("[DNS] DNS Record for %v doesn't exists, no need to change DNS.\n", fqdn) - } else { - fpatcherr := fzone.SendPATCH(strings.Replace(fqdn+".", "."+fzone.Name, "", 1), addr.String(), recordtype, "DELETE") - if fpatcherr != nil { - return fpatcherr - } - fmt.Printf("[DNS] - %v IN %v %v\n", fqdn, recordtype, addr.String()) - } - } + if !frecordexists { + fmt.Printf("[DNS] DNS Record for %v doesn't exists, no need to change DNS.\n", fqdn) + } else { + fpatcherr := fzone.SendPATCH(strings.Replace(fqdn+".", "."+fzone.Name, "", 1), addr.String(), recordtype, "DELETE") + if fpatcherr != nil { + return fpatcherr + } + fmt.Printf("[DNS] - %v IN %v %v\n", fqdn, recordtype, addr.String()) + } + } - baseip := addr.StringExpanded() - var rfqdn string - if addr.Is4() { - a := strings.Split(baseip, ".") - b := reverse(a) - rfqdn = strings.Join(b, ".") + ".in-addr.arpa" - } else if addr.Is6() { - a := strings.Replace(baseip, ":", "", -1) - b := strings.Split(a, "") - c := reverse(b) - rfqdn = strings.Join(c, ".") + ".ip6.arpa" - } + baseip := addr.StringExpanded() + var rfqdn string + if addr.Is4() { + a := strings.Split(baseip, ".") + b := reverse(a) + rfqdn = strings.Join(b, ".") + ".in-addr.arpa" + } else if addr.Is6() { + a := strings.Replace(baseip, ":", "", -1) + b := strings.Split(a, "") + c := reverse(b) + rfqdn = strings.Join(c, ".") + ".ip6.arpa" + } - rzone, rzoneerr := GetBestDNSZone(rfqdn) - if rzoneerr != nil { - fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS delete op\n", rfqdn) - } else { - _, rrecordexists := rzone.GetRecord(rfqdn, "PTR", fqdn) - rhost := strings.Replace(rfqdn+".", "."+rzone.Name, "", 1) + rzone, rzoneerr := GetBestDNSZone(rfqdn) + if rzoneerr != nil { + fmt.Printf("[DNS] No suitable zone found for %v, skipping DNS delete op\n", rfqdn) + } else { + _, rrecordexists := rzone.GetRecord(rfqdn, "PTR", fqdn) + rhost := strings.Replace(rfqdn+".", "."+rzone.Name, "", 1) - if !rrecordexists { - fmt.Printf("[DNS] Reverse DNS Record for %v doesn't exists, no need to change DNS.\n", addr.String()) - } else { - rpatcherr := rzone.SendPATCH(rhost, fqdn, "PTR", "DELETE") - if rpatcherr != nil { - return rpatcherr - } - fmt.Printf("[DNS] - %v IN %v %v\n", rfqdn, "PTR", fqdn) - } - } + if !rrecordexists { + fmt.Printf("[DNS] Reverse DNS Record for %v doesn't exists, no need to change DNS.\n", addr.String()) + } else { + rpatcherr := rzone.SendPATCH(rhost, fqdn, "PTR", "DELETE") + if rpatcherr != nil { + return rpatcherr + } + fmt.Printf("[DNS] - %v IN %v %v\n", rfqdn, "PTR", fqdn) + } + } - return nil + return nil } diff --git a/cmd/root.go b/cmd/root.go index 211d4cf..2c1b1c7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,73 +5,73 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "os" + "fmt" + "os" - "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) var rootCmd = &cobra.Command{ - Use: "ipam", - Short: "A cli based ipam", - Long: `A cli based ipam. + Use: "ipam", + Short: "A cli based ipam", + Long: `A cli based ipam. You can manage subnets, single ip addresses within those, and the corresponding A records. PowerDNS and IPV6-Support will follow`, - Version: ipam_version, + Version: ipam_version, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } } func init() { - cobra.OnInitialize(initConfig) + cobra.OnInitialize(initConfig) - rootCmd.Flags().BoolP("debug", "d", false, "Enable debug mode. (may print sensitive Information, so please watch out!)") + rootCmd.Flags().BoolP("debug", "d", false, "Enable debug mode. (may print sensitive Information, so please watch out!)") } func initConfig() { - // Find home directory. - homedir, err := os.UserHomeDir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } + // Find home directory. + homedir, err := os.UserHomeDir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } - var ipamdir string = homedir + "/.ipam/" - // Search config in home directory with name ".cobra" (without extension). - viper.AddConfigPath(ipamdir) - viper.SetConfigName("ipam") - viper.SetConfigType("yaml") + var ipamdir string = homedir + "/.ipam/" + // Search config in home directory with name ".cobra" (without extension). + viper.AddConfigPath(ipamdir) + viper.SetConfigName("ipam") + viper.SetConfigType("yaml") - viper.SetDefault("DataPath", ipamdir+"data/") - viper.SetDefault("PowerDNSEnabled", false) - viper.SetDefault("PowerDNSEndpoint", "") - viper.SetDefault("PowerDNSApiKey", "") + viper.SetDefault("DataPath", ipamdir+"data/") + viper.SetDefault("PowerDNSEnabled", false) + viper.SetDefault("PowerDNSEndpoint", "") + viper.SetDefault("PowerDNSApiKey", "") - if err := viper.ReadInConfig(); err != nil { - _, patherr := os.Stat(ipamdir) - if patherr != nil { - mkerr := os.MkdirAll(ipamdir, 0755) - if mkerr != nil { - println("[ERROR] Can't create ipam config directory!", mkerr) - } - } + if err := viper.ReadInConfig(); err != nil { + _, patherr := os.Stat(ipamdir) + if patherr != nil { + mkerr := os.MkdirAll(ipamdir, 0755) + if mkerr != nil { + println("[ERROR] Can't create ipam config directory!", mkerr) + } + } - // I have no idea what's happening here... - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - writeerr := viper.SafeWriteConfig() - if writeerr != nil { - println("[ERROR] Can't write config file!", writeerr) - } - } else { - println("[ERROR] Can't read config file!", err) - } - } + // I have no idea what's happening here... + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + writeerr := viper.SafeWriteConfig() + if writeerr != nil { + println("[ERROR] Can't write config file!", writeerr) + } + } else { + println("[ERROR] Can't read config file!", err) + } + } } diff --git a/cmd/storage.go b/cmd/storage.go index 334d662..6873c83 100644 --- a/cmd/storage.go +++ b/cmd/storage.go @@ -5,14 +5,14 @@ Copyright © 2023 Laura Kalb package cmd import ( - "encoding/json" - "fmt" - "net/netip" - "os" - "sort" - "strings" + "encoding/json" + "fmt" + "net/netip" + "os" + "sort" + "strings" - "github.com/spf13/viper" + "github.com/spf13/viper" ) // FindBestSubnet tries to load the most fitting IP subnet file @@ -22,71 +22,71 @@ import ( // Returns the best subnet as Subnet object and true if a suitable // subnet was found, otherwise an empty Subnet object and false. func FindBestSubnet(ip netip.Addr) (Subnet, bool) { - subnets := ListSubnets() - var smallestprefix int = 0 - bestmatch, _ := netip.ParsePrefix("0.0.0.0/32") - var isipv4 bool = ip.Is4() - var subnet Subnet + subnets := ListSubnets() + var smallestprefix int = 0 + bestmatch, _ := netip.ParsePrefix("0.0.0.0/32") + var isipv4 bool = ip.Is4() + var subnet Subnet - for _, net := range subnets { - prefix, _ := netip.ParsePrefix(net) - if prefix.Addr().Is4() == isipv4 { - if prefix.Contains(ip) { - if prefix.Bits() > smallestprefix { - bestmatch = prefix - } - } - } - } - if !bestmatch.Addr().IsUnspecified() { - var geterr error - subnet, geterr = GetSubnet(bestmatch) - if geterr != nil { - fmt.Println("[ERROR]", geterr) - os.Exit(1) - } - return subnet, true - } else { - return Subnet{}, false - } + for _, net := range subnets { + prefix, _ := netip.ParsePrefix(net) + if prefix.Addr().Is4() == isipv4 { + if prefix.Contains(ip) { + if prefix.Bits() > smallestprefix { + bestmatch = prefix + } + } + } + } + if !bestmatch.Addr().IsUnspecified() { + var geterr error + subnet, geterr = GetSubnet(bestmatch) + if geterr != nil { + fmt.Println("[ERROR]", geterr) + os.Exit(1) + } + return subnet, true + } else { + return Subnet{}, false + } } // SubnetExists will return true if the given subnet already exists // on file, false otherwise. func SubnetExists(net netip.Prefix) bool { - subnets := ListSubnets() + subnets := ListSubnets() - for _, b := range subnets { - if b == net.String() { - return true - } - } - return false + for _, b := range subnets { + if b == net.String() { + return true + } + } + return false } // ListSubnets returns a list of strings containing the current // subnets configured. func ListSubnets() []string { - subnets := make([]string, 0) - var datadir string = viper.GetString("DataPath") + subnets := make([]string, 0) + var datadir string = viper.GetString("DataPath") - subnetfiles, readerr := os.ReadDir(datadir) + subnetfiles, readerr := os.ReadDir(datadir) - if len(subnetfiles) == 0 { - return subnets - } + if len(subnetfiles) == 0 { + return subnets + } - if readerr != nil { - fmt.Println("[ERROR]", readerr) - os.Exit(1) - } - for _, element := range subnetfiles { - a := strings.Replace(element.Name(), "_", "/", 1) - a = strings.Replace(a, ".json", "", 1) - subnets = append(subnets, a) - } + if readerr != nil { + fmt.Println("[ERROR]", readerr) + os.Exit(1) + } + for _, element := range subnetfiles { + a := strings.Replace(element.Name(), "_", "/", 1) + a = strings.Replace(a, ".json", "", 1) + subnets = append(subnets, a) + } - return subnets + return subnets } // WriteSubnet takes a given Subnet object and tries to write it to @@ -94,35 +94,35 @@ func ListSubnets() []string { // // Returns nil on success or the error that happened. func (s Subnet) WriteSubnet() error { - var datadir string = viper.GetString("DataPath") + var datadir string = viper.GetString("DataPath") - _, direrr := os.Stat(datadir) - if direrr != nil { - mkerr := os.MkdirAll(datadir, 0755) - if mkerr != nil { - println("[ERROR] Can't create ipam config directory!", mkerr) - os.Exit(1) - } - } + _, direrr := os.Stat(datadir) + if direrr != nil { + mkerr := os.MkdirAll(datadir, 0755) + if mkerr != nil { + println("[ERROR] Can't create ipam config directory!", mkerr) + os.Exit(1) + } + } - filename := datadir + strings.Replace(s.Subnet.String(), "/", "_", 1) + ".json" + filename := datadir + strings.Replace(s.Subnet.String(), "/", "_", 1) + ".json" - data, _ := json.Marshal(s) + data, _ := json.Marshal(s) - file, fileerr := os.Create(filename) - if fileerr != nil { - fmt.Println("[ERROR]", fileerr) - os.Exit(1) - } - defer file.Close() + file, fileerr := os.Create(filename) + if fileerr != nil { + fmt.Println("[ERROR]", fileerr) + os.Exit(1) + } + defer file.Close() - _, writeerr := file.Write(data) - if writeerr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } + _, writeerr := file.Write(data) + if writeerr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } - return nil + return nil } // GetSubnet reads the corresponding file for the given @@ -131,35 +131,35 @@ func (s Subnet) WriteSubnet() error { // Returns the Subnet object and nil if the file read was // successful, an empty Subnet object and the error otherwise. func GetSubnet(net netip.Prefix) (Subnet, error) { - var datadir string = viper.GetString("DataPath") - filename := datadir + strings.Replace(net.String(), "/", "_", 1) + ".json" - var subnet Subnet = Subnet{} + var datadir string = viper.GetString("DataPath") + filename := datadir + strings.Replace(net.String(), "/", "_", 1) + ".json" + var subnet Subnet = Subnet{} - content, readerr := os.ReadFile(filename) - if readerr != nil { - return Subnet{}, readerr - } + content, readerr := os.ReadFile(filename) + if readerr != nil { + return Subnet{}, readerr + } - marsherr := json.Unmarshal(content, &subnet) - if marsherr != nil { - return Subnet{}, marsherr - } + marsherr := json.Unmarshal(content, &subnet) + if marsherr != nil { + return Subnet{}, marsherr + } - return subnet, nil + return subnet, nil } // SortAddresses sorts the given list of IP addresses // using netip.Addr.Less() and returns the sorted slice. func SortAddresses(list []Address) []Address { - if len(list) <= 1 { - return list - } + if len(list) <= 1 { + return list + } - sort.Slice(list, func(i, j int) bool { - return list[i].IP.Less(list[j].IP) - }) - return list + sort.Slice(list, func(i, j int) bool { + return list[i].IP.Less(list[j].IP) + }) + return list } // DeleteSubnet deletes the subnet file on disk for netip.Prefix @@ -167,13 +167,13 @@ func SortAddresses(list []Address) []Address { // // Returns nil on success, or a *PathError on failure func DeleteSubnet(net netip.Prefix) error { - var datadir string = viper.GetString("DataPath") - filename := datadir + strings.Replace(net.String(), "/", "_", 1) + ".json" + var datadir string = viper.GetString("DataPath") + filename := datadir + strings.Replace(net.String(), "/", "_", 1) + ".json" - removeerr := os.Remove(filename) - if removeerr != nil { - return removeerr - } else { - return nil - } + removeerr := os.Remove(filename) + if removeerr != nil { + return removeerr + } else { + return nil + } } diff --git a/cmd/subnet-add.go b/cmd/subnet-add.go index 8f867eb..51e1ba9 100644 --- a/cmd/subnet-add.go +++ b/cmd/subnet-add.go @@ -5,92 +5,92 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" - "os/user" - "time" + "fmt" + "net/netip" + "os" + "os/user" + "time" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // addCmd represents the add command var subnetaddCmd = &cobra.Command{ - Use: "add subnet subnet-name [vlan]", - Short: "Add a new subnet", - Long: `Add a new subnet`, - Args: cobra.RangeArgs(2, 3), - Aliases: []string{"a"}, - Run: func(cmd *cobra.Command, args []string) { - var subnet string - var vlanid string - var netname string + Use: "add subnet subnet-name [vlan]", + Short: "Add a new subnet", + Long: `Add a new subnet`, + Args: cobra.RangeArgs(2, 3), + Aliases: []string{"a"}, + Run: func(cmd *cobra.Command, args []string) { + var subnet string + var vlanid string + var netname string - if len(args) == 2 { - subnet = args[0] - netname = args[1] - vlanid = "-" - } + if len(args) == 2 { + subnet = args[0] + netname = args[1] + vlanid = "-" + } - if len(args) == 3 { - subnet = args[0] - netname = args[1] - vlanid = args[2] - } + if len(args) == 3 { + subnet = args[0] + netname = args[1] + vlanid = args[2] + } - // Parse subnet into ParseCIDR to test if it's a valid subnet - // _, ipnet, err := net.ParseCIDR(subnet) - ipnet, parseerr := netip.ParsePrefix(subnet) + // Parse subnet into ParseCIDR to test if it's a valid subnet + // _, ipnet, err := net.ParseCIDR(subnet) + ipnet, parseerr := netip.ParsePrefix(subnet) - // Exit if subnet already exists, no need to add it then - if SubnetExists(ipnet) { - fmt.Printf("[ERROR] Subnet already exists: %v\n", subnet) - os.Exit(1) - } + // Exit if subnet already exists, no need to add it then + if SubnetExists(ipnet) { + fmt.Printf("[ERROR] Subnet already exists: %v\n", subnet) + os.Exit(1) + } - // Exit if parsed value is no valid IP - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + // Exit if parsed value is no valid IP + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - // Exit if parsed value is an IPv6 Address - // TODO: Implement IPv6 support - if !ipnet.Addr().Is4() { - fmt.Printf("[ERROR] IPv6 is not yet supported!\n") - os.Exit(1) - } + // Exit if parsed value is an IPv6 Address + // TODO: Implement IPv6 support + // if !ipnet.Addr().Is4() { + // fmt.Printf("[ERROR] IPv6 is not yet supported!\n") + // os.Exit(1) + // } - currentuser, _ := user.Current() + currentuser, _ := user.Current() - subnetobject := Subnet{} - subnetobject.Subnet = ipnet - subnetobject.Name = netname - subnetobject.Vlan = vlanid - subnetobject.ChangedAt = time.Now() - subnetobject.ChangedBy = currentuser.Username + subnetobject := Subnet{} + subnetobject.Subnet = ipnet + subnetobject.Name = netname + subnetobject.Vlan = vlanid + subnetobject.ChangedAt = time.Now() + subnetobject.ChangedBy = currentuser.Username - writeerr := subnetobject.WriteSubnet() + writeerr := subnetobject.WriteSubnet() - if writeerr != nil { - fmt.Println("[ERROR]", writeerr) - os.Exit(1) - } + if writeerr != nil { + fmt.Println("[ERROR]", writeerr) + os.Exit(1) + } - fmt.Printf("added subnet:\nnet: %v\nname: %v\nvlan: %v\n", subnet, netname, vlanid) - }, + fmt.Printf("added subnet:\nnet: %v\nname: %v\nvlan: %v\n", subnet, netname, vlanid) + }, } func init() { - subnetCmd.AddCommand(subnetaddCmd) + subnetCmd.AddCommand(subnetaddCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // addCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // addCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/subnet-delete.go b/cmd/subnet-delete.go index 17fb64c..60cba3d 100644 --- a/cmd/subnet-delete.go +++ b/cmd/subnet-delete.go @@ -4,82 +4,82 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" + "fmt" + "net/netip" + "os" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // deleteCmd represents the delete command var subnetdeleteCmd = &cobra.Command{ - Use: "delete", - Short: "delete subnet", - Long: `Delete a subnet from the ipam.`, - Args: cobra.ExactArgs(1), - Aliases: []string{"d"}, - Example: "ipam subnet delete 192.168.0.0/24", - Run: func(cmd *cobra.Command, args []string) { - subnet, parseerr := netip.ParsePrefix(args[0]) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + Use: "delete", + Short: "delete subnet", + Long: `Delete a subnet from the ipam.`, + Args: cobra.ExactArgs(1), + Aliases: []string{"d"}, + Example: "ipam subnet delete 192.168.0.0/24", + Run: func(cmd *cobra.Command, args []string) { + subnet, parseerr := netip.ParsePrefix(args[0]) + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - if !SubnetExists(subnet) { - fmt.Printf("[ERROR] Couldn't find subnet %v\n", subnet.String()) - os.Exit(1) - } + if !SubnetExists(subnet) { + fmt.Printf("[ERROR] Couldn't find subnet %v\n", subnet.String()) + os.Exit(1) + } - subnetobj, suberr := GetSubnet(subnet) - if suberr != nil { - fmt.Println("[ERROR]", suberr) - os.Exit(1) - } + subnetobj, suberr := GetSubnet(subnet) + if suberr != nil { + fmt.Println("[ERROR]", suberr) + os.Exit(1) + } - var confirmation string - skipinteractive, _ := cmd.Flags().GetBool("yes") - if skipinteractive { - confirmation = "y" - } else { - fmt.Printf("[WARNING] Do you really want to delete subnet %v?\n", subnet.String()) - fmt.Printf("[WARNING] This will also delete all DNS records if PowerDNS integration is enabled!\n") - fmt.Printf("[WARNING] Continue? [y/N] ") - fmt.Scan(&confirmation) - } + var confirmation string + skipinteractive, _ := cmd.Flags().GetBool("yes") + if skipinteractive { + confirmation = "y" + } else { + fmt.Printf("[WARNING] Do you really want to delete subnet %v?\n", subnet.String()) + fmt.Printf("[WARNING] This will also delete all DNS records if PowerDNS integration is enabled!\n") + fmt.Printf("[WARNING] Continue? [y/N] ") + fmt.Scan(&confirmation) + } - if (confirmation == "y") || (confirmation == "Y") { - for _, address := range subnetobj.Addresses { - if address.FQDN != "" { - deleteerr := DeleteDNSFqdn(address.FQDN, address.IP) - if deleteerr != nil { - fmt.Println("[ERROR]", deleteerr) - } - } - } - deleteerr := DeleteSubnet(subnet) - if deleteerr != nil { - fmt.Println("[ERROR]", deleteerr) - os.Exit(1) - } else { - fmt.Printf("deleted subnet %v\n", subnet.String()) - } + if (confirmation == "y") || (confirmation == "Y") { + for _, address := range subnetobj.Addresses { + if address.FQDN != "" { + deleteerr := DeleteDNSFqdn(address.FQDN, address.IP) + if deleteerr != nil { + fmt.Println("[ERROR]", deleteerr) + } + } + } + deleteerr := DeleteSubnet(subnet) + if deleteerr != nil { + fmt.Println("[ERROR]", deleteerr) + os.Exit(1) + } else { + fmt.Printf("deleted subnet %v\n", subnet.String()) + } - } - }, + } + }, } func init() { - subnetCmd.AddCommand(subnetdeleteCmd) + subnetCmd.AddCommand(subnetdeleteCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - subnetdeleteCmd.Flags().BoolP("yes", "y", false, "suppress interactive prompts and answer yes.") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + subnetdeleteCmd.Flags().BoolP("yes", "y", false, "suppress interactive prompts and answer yes.") } diff --git a/cmd/subnet-list.go b/cmd/subnet-list.go index b47e5e3..e7b1ef6 100644 --- a/cmd/subnet-list.go +++ b/cmd/subnet-list.go @@ -4,85 +4,85 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "math" - "net/netip" - "os" - "sort" + "fmt" + "math" + "net/netip" + "os" + "sort" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // listCmd represents the list command var subnetlistCmd = &cobra.Command{ - Use: "list", - Short: "List all subnets", - Long: `List all subnets`, - Aliases: []string{"l"}, - Args: cobra.ExactArgs(0), - Example: "cmdb subnet list", - Run: func(cmd *cobra.Command, args []string) { - //verbose, _ := cmd.Flags().GetBool("verbose") - subnetlist := ListSubnets() - var subnets []Subnet + Use: "list", + Short: "List all subnets", + Long: `List all subnets`, + Aliases: []string{"l"}, + Args: cobra.ExactArgs(0), + Example: "cmdb subnet list", + Run: func(cmd *cobra.Command, args []string) { + //verbose, _ := cmd.Flags().GetBool("verbose") + subnetlist := ListSubnets() + var subnets []Subnet - for _, subnet := range subnetlist { - prefix, _ := netip.ParsePrefix(subnet) - net, err := GetSubnet(prefix) - if err != nil { - fmt.Println("[ERROR]", err) - os.Exit(1) - } - subnets = append(subnets, net) - } - sort.Slice(subnets, func(i, j int) bool { - return subnets[i].Subnet.Addr().Less(subnets[j].Subnet.Addr()) - }) + for _, subnet := range subnetlist { + prefix, _ := netip.ParsePrefix(subnet) + net, err := GetSubnet(prefix) + if err != nil { + fmt.Println("[ERROR]", err) + os.Exit(1) + } + subnets = append(subnets, net) + } + sort.Slice(subnets, func(i, j int) bool { + return subnets[i].Subnet.Addr().Less(subnets[j].Subnet.Addr()) + }) - fmt.Printf("%-15s VLAN %-25s Free IPs\n", "Prefix", "Name") + fmt.Printf("%-18s VLAN %-25s Free IPs\n", "Prefix", "Name") - for _, subnet := range subnets { - var numip, freeip int + for _, subnet := range subnets { + var numip, freeip int - if subnet.Subnet.Addr().Is4() { - hostbits := float64(32 - subnet.Subnet.Bits()) - if subnet.Subnet.Bits() == 31 { - numip = 2 - } else { - numip = int(math.Pow(2, hostbits)) - 2 - } + if subnet.Subnet.Addr().Is4() { + hostbits := float64(32 - subnet.Subnet.Bits()) + if subnet.Subnet.Bits() == 31 { + numip = 2 + } else { + numip = int(math.Pow(2, hostbits)) - 2 + } - freeip = numip - len(subnet.Addresses) + freeip = numip - len(subnet.Addresses) - if freeip > 1000 { + if freeip > 1000 { - fmt.Printf("%-18s %-4s %-25s >1000\n", subnet.Subnet, subnet.Vlan, subnet.Name) - } else { - //fmt.Printf("| %-20s | %-20s |\n", "vegetables", "fruits") - fmt.Printf("%-18s %-4s %-25s %v\n", subnet.Subnet, subnet.Vlan, subnet.Name, freeip) - } - } else { - fmt.Printf("%v:\t%v\t(vl: %v)\n", subnet.Subnet, subnet.Name, subnet.Vlan) - //todo - } - //} else { - // fmt.Printf("%v:\t%v\t(vl: %v)\n", subnet.Subnet, subnet.Name, subnet.Vlan) - //} + fmt.Printf("%-18s %-4s %-25s >1000\n", subnet.Subnet, subnet.Vlan, subnet.Name) + } else { + //fmt.Printf("| %-20s | %-20s |\n", "vegetables", "fruits") + fmt.Printf("%-18s %-4s %-25s %v\n", subnet.Subnet, subnet.Vlan, subnet.Name, freeip) + } + } else { + fmt.Printf("%v:\t%v\t(vl: %v)\n", subnet.Subnet, subnet.Name, subnet.Vlan) + //todo + } + //} else { + // fmt.Printf("%v:\t%v\t(vl: %v)\n", subnet.Subnet, subnet.Name, subnet.Vlan) + //} - } - }, + } + }, } func init() { - subnetCmd.AddCommand(subnetlistCmd) + subnetCmd.AddCommand(subnetlistCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // listCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // listCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // subnetlistCmd.Flags().BoolP("verbose", "v", false, "Show verbose output like free IPs") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // subnetlistCmd.Flags().BoolP("verbose", "v", false, "Show verbose output like free IPs") } diff --git a/cmd/subnet-show.go b/cmd/subnet-show.go index dcc7a25..8796cda 100644 --- a/cmd/subnet-show.go +++ b/cmd/subnet-show.go @@ -4,69 +4,69 @@ Copyright © 2023 Laura Kalb package cmd import ( - "fmt" - "net/netip" - "os" - "time" + "fmt" + "net/netip" + "os" + "time" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // showCmd represents the show command var subnetshowCmd = &cobra.Command{ - Use: "show subnet", - Short: "Displays a subnet.", - Long: `Displays a subnets details like name and vlan tag, + Use: "show subnet", + Short: "Displays a subnet.", + Long: `Displays a subnets details like name and vlan tag, aswell as a list of containing IP addresses`, - Args: cobra.ExactArgs(1), - Aliases: []string{"s"}, - Example: "ipam subnet show 192.168.0.0/24\nipam subnet show 2001:db8::/64", - Run: func(cmd *cobra.Command, args []string) { - net, parseerr := netip.ParsePrefix(args[0]) + Args: cobra.ExactArgs(1), + Aliases: []string{"s"}, + Example: "ipam subnet show 192.168.0.0/24\nipam subnet show 2001:db8::/64", + Run: func(cmd *cobra.Command, args []string) { + net, parseerr := netip.ParsePrefix(args[0]) - if parseerr != nil { - fmt.Println("[ERROR]", parseerr) - os.Exit(1) - } + if parseerr != nil { + fmt.Println("[ERROR]", parseerr) + os.Exit(1) + } - if !SubnetExists(net) { - fmt.Printf("[ERROR] no subnet found for prefix: %v\n", args[0]) - os.Exit(1) - } + if !SubnetExists(net) { + fmt.Printf("[ERROR] no subnet found for prefix: %v\n", args[0]) + os.Exit(1) + } - subnet, subneterr := GetSubnet(net) - if subneterr != nil { - fmt.Println("[ERROR]", subneterr) - os.Exit(1) - } - fmt.Printf("\n") - fmt.Printf("Name: %v\n", subnet.Name) - fmt.Printf("Vlan: %v\n", subnet.Vlan) - fmt.Printf("Prefix: %v\n", subnet.Subnet) - fmt.Printf("Modified at: %v\n", subnet.ChangedAt.Format(time.RFC1123)) - fmt.Printf("Modified by: %v\n\n", subnet.ChangedBy) + subnet, subneterr := GetSubnet(net) + if subneterr != nil { + fmt.Println("[ERROR]", subneterr) + os.Exit(1) + } + fmt.Printf("\n") + fmt.Printf("Name: %v\n", subnet.Name) + fmt.Printf("Vlan: %v\n", subnet.Vlan) + fmt.Printf("Prefix: %v\n", subnet.Subnet) + fmt.Printf("Modified at: %v\n", subnet.ChangedAt.Format(time.RFC1123)) + fmt.Printf("Modified by: %v\n\n", subnet.ChangedBy) - fmt.Printf("%v:\n", subnet.Subnet) - for _, element := range subnet.Addresses { - if element.FQDN == "" { - fmt.Printf("\t%v\n", element.IP.String()) - } else { - fmt.Printf("\t%v: %v\n", element.IP.String(), element.FQDN) - } - } - }, + fmt.Printf("%v:\n", subnet.Subnet) + for _, element := range subnet.Addresses { + if element.FQDN == "" { + fmt.Printf("\t%v\n", element.IP.String()) + } else { + fmt.Printf("\t%v: %v\n", element.IP.String(), element.FQDN) + } + } + }, } func init() { - subnetCmd.AddCommand(subnetshowCmd) + subnetCmd.AddCommand(subnetshowCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // showCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // showCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // showCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // showCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/subnet.go b/cmd/subnet.go index befd1f0..7d16d38 100644 --- a/cmd/subnet.go +++ b/cmd/subnet.go @@ -5,27 +5,27 @@ Copyright © 2023 Laura Kalb package cmd import ( - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) // subnetCmd represents the subnet command var subnetCmd = &cobra.Command{ - Use: "subnet", - Short: "Manage ip subnets", - Long: `Manage ip subnets`, - Aliases: []string{"s"}, + Use: "subnet", + Short: "Manage ip subnets", + Long: `Manage ip subnets`, + Aliases: []string{"s"}, } func init() { - rootCmd.AddCommand(subnetCmd) + rootCmd.AddCommand(subnetCmd) - // Here you will define your flags and configuration settings. + // Here you will define your flags and configuration settings. - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // subnetCmd.PersistentFlags().String("foo", "", "A help for foo") + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // subnetCmd.PersistentFlags().String("foo", "", "A help for foo") - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // subnetCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // subnetCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/main.go b/main.go index 190860d..e6d295c 100644 --- a/main.go +++ b/main.go @@ -7,5 +7,5 @@ package main import "git.sr.ht/~lauralani/ipam/cmd" func main() { - cmd.Execute() + cmd.Execute() }