mirror of
https://codeberg.org/lauralani/ipam.git
synced 2024-11-23 20:20:39 +01:00
Merge pull request 'Renamed GO module name and fixed whitespace issues' (#10) from rename-go-module-name into main
Reviewed-on: https://codeberg.org/lauralani/ipam/pulls/10
This commit is contained in:
commit
df3f3d6782
19 changed files with 667 additions and 669 deletions
|
@ -5,32 +5,32 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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"`
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
package cmd
|
||||
|
||||
const (
|
||||
ipamVersion = "0.2.0"
|
||||
ipamVersion = "0.2.0"
|
||||
)
|
||||
|
|
142
cmd/export.go
142
cmd/export.go
|
@ -5,92 +5,92 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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 ipam configuration",
|
||||
Long: `Export current ipam contents to importable data format.
|
||||
Use: "export",
|
||||
Short: "Export ipam configuration",
|
||||
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.")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
112
cmd/ip-delete.go
112
cmd/ip-delete.go
|
@ -4,78 +4,78 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
currentuser, _ := user.Current()
|
||||
subnet.ChangedAt = time.Now()
|
||||
subnet.ChangedBy = currentuser.Username
|
||||
currentuser, _ := user.Current()
|
||||
subnet.ChangedAt = time.Now()
|
||||
subnet.ChangedBy = 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 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")
|
||||
}
|
||||
|
|
|
@ -4,32 +4,32 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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")
|
||||
}
|
||||
|
|
|
@ -4,60 +4,60 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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 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, vlan %v)\n", subnet.Subnet.String(), subnet.Name, subnet.Vlan)
|
||||
fmt.Printf("Modified at: %v\n", subnet.ChangedAt.Format(time.RFC1123))
|
||||
fmt.Printf("Modified by: %v\n", subnet.ChangedBy)
|
||||
},
|
||||
fmt.Printf("IP: %v\n", ip.String())
|
||||
fmt.Printf("FQDN: %v\n", addr.FQDN)
|
||||
fmt.Printf("Subnet: %v (%v, vlan %v)\n", subnet.Subnet.String(), subnet.Name, subnet.Vlan)
|
||||
fmt.Printf("Modified at: %v\n", subnet.ChangedAt.Format(time.RFC1123))
|
||||
fmt.Printf("Modified by: %v\n", subnet.ChangedBy)
|
||||
},
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
|
26
cmd/ip.go
26
cmd/ip.go
|
@ -5,27 +5,27 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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 and show IP addresses`,
|
||||
Aliases: []string{"i"},
|
||||
Use: "ip",
|
||||
Short: "manage IP addresses",
|
||||
Long: `Add, delete 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")
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ func GetBestDNSZone(fqdn string) (DNSZone, error) {
|
|||
}
|
||||
|
||||
var bestmatch DNSZone
|
||||
var matchfound bool = false
|
||||
var matchfound = false
|
||||
|
||||
for _, zone := range zones {
|
||||
if strings.HasSuffix(fqdn, "."+zone.Name) {
|
||||
|
@ -288,7 +288,7 @@ func AddDNSFqdn(fqdn string, addr netip.Addr) error {
|
|||
if frecordexists {
|
||||
fmt.Printf("[DNS] DNS Record for %v already exists, no need to change DNS.\n", fqdn)
|
||||
} else {
|
||||
var dotfqdn, dotfzone string = fqdn + ".", "." + fzone.Name
|
||||
var dotfqdn, dotfzone = fqdn + ".", "." + fzone.Name
|
||||
record := strings.Replace(dotfqdn, dotfzone, "", 1)
|
||||
fpatcherr := fzone.SendPATCH(record, addr.String(), recordtype, "REPLACE")
|
||||
if fpatcherr != nil {
|
||||
|
|
94
cmd/root.go
94
cmd/root.go
|
@ -5,73 +5,73 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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 and single IP addresses within those subnets.
|
||||
ipam can also manage the corresponding DNS records in your PowerDNS Instance.`,
|
||||
Version: ipamVersion,
|
||||
Version: ipamVersion,
|
||||
}
|
||||
|
||||
// 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 = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
212
cmd/storage.go
212
cmd/storage.go
|
@ -5,14 +5,14 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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("::/128")
|
||||
var isipv4 bool = ip.Is4()
|
||||
var subnet Subnet
|
||||
subnets := ListSubnets()
|
||||
var smallestprefix = 0
|
||||
bestmatch, _ := netip.ParsePrefix("::/128")
|
||||
var isipv4 = 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 = 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 = 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 = viper.GetString("DataPath")
|
||||
filename := datadir + strings.Replace(net.String(), "/", "_", 1) + ".json"
|
||||
var 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 = 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,83 +5,83 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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)
|
||||
|
||||
}
|
||||
|
|
|
@ -4,82 +4,82 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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.")
|
||||
}
|
||||
|
|
|
@ -4,85 +4,85 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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("%-18s 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")
|
||||
}
|
||||
|
|
|
@ -4,90 +4,88 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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)
|
||||
//fmt.Printf("%v:\n", subnet.Subnet)
|
||||
|
||||
addrlist := SortAddresses(subnet.Addresses)
|
||||
addrlist := SortAddresses(subnet.Addresses)
|
||||
|
||||
if subnet.Subnet.Addr().Is4() {
|
||||
if subnet.Subnet.Addr().Is4() {
|
||||
|
||||
fmt.Printf("%-15s Hostname\n", "IP Address")
|
||||
for _, element := range addrlist {
|
||||
if element.FQDN == "" {
|
||||
fmt.Printf("%v\n", element.IP.String())
|
||||
} else {
|
||||
fmt.Printf("%-15s %v\n", element.IP.String(), element.FQDN)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%-15s Hostname\n", "IP Address")
|
||||
for _, element := range addrlist {
|
||||
if element.FQDN == "" {
|
||||
fmt.Printf("%v\n", element.IP.String())
|
||||
} else {
|
||||
fmt.Printf("%-15s %v\n", element.IP.String(), element.FQDN)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
fmt.Printf("%-39s Hostname\n", "IP Address")
|
||||
fmt.Printf("%-39s Hostname\n", "IP Address")
|
||||
|
||||
for _, element := range addrlist {
|
||||
if element.FQDN == "" {
|
||||
fmt.Printf("%v\n", element.IP.String())
|
||||
} else {
|
||||
fmt.Printf("%-39s %v\n", element.IP.String(), element.FQDN)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, element := range addrlist {
|
||||
if element.FQDN == "" {
|
||||
fmt.Printf("%v\n", element.IP.String())
|
||||
} else {
|
||||
fmt.Printf("%-39s %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")
|
||||
}
|
||||
|
|
|
@ -5,27 +5,27 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
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: `Add, delete and show IP subnets`,
|
||||
Aliases: []string{"s"},
|
||||
Use: "subnet",
|
||||
Short: "Manage IP subnets",
|
||||
Long: `Add, delete and show 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")
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
|||
module git.sr.ht/~lauralani/ipam
|
||||
module codeberg.org/lauralani/ipam
|
||||
|
||||
go 1.20
|
||||
|
||||
|
|
18
go.sum
18
go.sum
|
@ -48,6 +48,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
|
|||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
@ -55,6 +56,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -96,6 +98,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
|
@ -128,24 +131,24 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
|
@ -167,6 +170,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
|
@ -186,7 +190,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -308,8 +311,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -321,8 +322,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -468,6 +467,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
|
|
4
main.go
4
main.go
|
@ -4,8 +4,8 @@ Copyright © 2023 Laura Kalb <dev@lauka.net>
|
|||
|
||||
package main
|
||||
|
||||
import "git.sr.ht/~lauralani/ipam/cmd"
|
||||
import "codeberg.org/lauralani/ipam/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
cmd.Execute()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue