diff --git a/cli/cmd/node/create_egress.go b/cli/cmd/node/create_egress.go new file mode 100644 index 00000000..cb2df2c1 --- /dev/null +++ b/cli/cmd/node/create_egress.go @@ -0,0 +1,39 @@ +package node + +import ( + "strings" + + "github.com/gravitl/netmaker/cli/functions" + "github.com/gravitl/netmaker/models" + "github.com/spf13/cobra" +) + +var ( + networkInterface string + natEnabled bool +) + +var nodeCreateEgressCmd = &cobra.Command{ + Use: "create_egress [NETWORK NAME] [NODE ID] [EGRESS GATEWAY ADDRESSES (comma separated)]", + Args: cobra.ExactArgs(3), + Short: "Turn a Node into a Egress", + Long: `Turn a Node into a Egress`, + Run: func(cmd *cobra.Command, args []string) { + egress := &models.EgressGatewayRequest{ + NetID: args[0], + NodeID: args[1], + Interface: networkInterface, + Ranges: strings.Split(args[2], ","), + } + if natEnabled { + egress.NatEnabled = "yes" + } + functions.PrettyPrint(functions.CreateEgress(args[0], args[1], egress)) + }, +} + +func init() { + nodeCreateEgressCmd.Flags().StringVar(&networkInterface, "interface", "", "Network interface name (ex:- eth0)") + nodeCreateEgressCmd.Flags().BoolVar(&natEnabled, "nat", false, "Enable NAT for Egress Traffic ?") + rootCmd.AddCommand(nodeCreateEgressCmd) +} diff --git a/cli/cmd/node/create_ingress.go b/cli/cmd/node/create_ingress.go new file mode 100644 index 00000000..dc46b6ed --- /dev/null +++ b/cli/cmd/node/create_ingress.go @@ -0,0 +1,23 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var failover bool + +var nodeCreateIngressCmd = &cobra.Command{ + Use: "create_ingress [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Turn a Node into a Ingress", + Long: `Turn a Node into a Ingress`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.CreateIngress(args[0], args[1], failover)) + }, +} + +func init() { + nodeCreateIngressCmd.Flags().BoolVar(&failover, "failover", false, "Enable FailOver ?") + rootCmd.AddCommand(nodeCreateIngressCmd) +} diff --git a/cli/cmd/node/create_relay.go b/cli/cmd/node/create_relay.go new file mode 100644 index 00000000..61e921ca --- /dev/null +++ b/cli/cmd/node/create_relay.go @@ -0,0 +1,22 @@ +package node + +import ( + "strings" + + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeCreateRelayCmd = &cobra.Command{ + Use: "create_relay [NETWORK NAME] [NODE ID] [RELAY ADDRESSES (comma separated)]", + Args: cobra.ExactArgs(3), + Short: "Turn a Node into a Relay", + Long: `Turn a Node into a Relay`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.CreateRelay(args[0], args[1], strings.Split(args[2], ","))) + }, +} + +func init() { + rootCmd.AddCommand(nodeCreateRelayCmd) +} diff --git a/cli/cmd/node/delete.go b/cli/cmd/node/delete.go new file mode 100644 index 00000000..501dd702 --- /dev/null +++ b/cli/cmd/node/delete.go @@ -0,0 +1,20 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeDeleteCmd = &cobra.Command{ + Use: "delete [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Delete a Node", + Long: `Delete a Node`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.DeleteNode(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeDeleteCmd) +} diff --git a/cli/cmd/node/delete_egress.go b/cli/cmd/node/delete_egress.go new file mode 100644 index 00000000..7d3d335b --- /dev/null +++ b/cli/cmd/node/delete_egress.go @@ -0,0 +1,20 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeDeleteEgressCmd = &cobra.Command{ + Use: "delete_egress [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Delete Egress role from a Node", + Long: `Delete Egress role from a Node`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.DeleteEgress(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeDeleteEgressCmd) +} diff --git a/cli/cmd/node/delete_ingress.go b/cli/cmd/node/delete_ingress.go new file mode 100644 index 00000000..3afe987d --- /dev/null +++ b/cli/cmd/node/delete_ingress.go @@ -0,0 +1,20 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeDeleteIngressCmd = &cobra.Command{ + Use: "delete_ingress [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Delete Ingress role from a Node", + Long: `Delete Ingress role from a Node`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.DeleteIngress(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeDeleteIngressCmd) +} diff --git a/cli/cmd/node/delete_relay.go b/cli/cmd/node/delete_relay.go new file mode 100644 index 00000000..ccef64f9 --- /dev/null +++ b/cli/cmd/node/delete_relay.go @@ -0,0 +1,20 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeDeleteRelayCmd = &cobra.Command{ + Use: "delete_relay [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Delete Relay role from a Node", + Long: `Delete Relay role from a Node`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.DeleteRelay(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeDeleteRelayCmd) +} diff --git a/cli/cmd/node/get.go b/cli/cmd/node/get.go new file mode 100644 index 00000000..ae3e91ae --- /dev/null +++ b/cli/cmd/node/get.go @@ -0,0 +1,20 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeGetCmd = &cobra.Command{ + Use: "get [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Get a node by ID", + Long: `Get a node by ID`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.GetNodeByID(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeGetCmd) +} diff --git a/cli/cmd/node/list.go b/cli/cmd/node/list.go new file mode 100644 index 00000000..6342f6c4 --- /dev/null +++ b/cli/cmd/node/list.go @@ -0,0 +1,28 @@ +package node + +import ( + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var networkName string + +// nodeListCmd lists all nodes +var nodeListCmd = &cobra.Command{ + Use: "list", + Args: cobra.NoArgs, + Short: "List all nodes", + Long: `List all nodes`, + Run: func(cmd *cobra.Command, args []string) { + if networkName != "" { + functions.PrettyPrint(functions.GetNodes(networkName)) + } else { + functions.PrettyPrint(functions.GetNodes()) + } + }, +} + +func init() { + nodeListCmd.Flags().StringVar(&networkName, "network", "", "Network name specifier") + rootCmd.AddCommand(nodeListCmd) +} diff --git a/cli/cmd/node/root.go b/cli/cmd/node/root.go new file mode 100644 index 00000000..85d0711f --- /dev/null +++ b/cli/cmd/node/root.go @@ -0,0 +1,37 @@ +package node + +import ( + "os" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "node", + Short: "Manage nodes associated with a network", + Long: `Manage nodes associated with a network`, + // Run: func(cmd *cobra.Command, args []string) { }, +} + +func GetRoot() *cobra.Command { + return rootCmd +} + +// 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) + } +} + +func init() { + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cli/cmd/node/uncordon.go b/cli/cmd/node/uncordon.go new file mode 100644 index 00000000..b9b094c2 --- /dev/null +++ b/cli/cmd/node/uncordon.go @@ -0,0 +1,22 @@ +package node + +import ( + "fmt" + + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var nodeUncordonCmd = &cobra.Command{ + Use: "uncordon [NETWORK NAME] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Get a node by ID", + Long: `Get a node by ID`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(*functions.UncordonNode(args[0], args[1])) + }, +} + +func init() { + rootCmd.AddCommand(nodeUncordonCmd) +} diff --git a/cli/cmd/node/update.go b/cli/cmd/node/update.go new file mode 100644 index 00000000..63fc52f2 --- /dev/null +++ b/cli/cmd/node/update.go @@ -0,0 +1,33 @@ +package node + +import ( + "encoding/json" + "log" + "os" + + "github.com/gravitl/netmaker/cli/functions" + "github.com/gravitl/netmaker/models" + "github.com/spf13/cobra" +) + +var nodeUpdateCmd = &cobra.Command{ + Use: "update [NETWORK NAME] [NODE ID] [/path/to/node_definition.json]", + Args: cobra.ExactArgs(3), + Short: "Update a Node", + Long: `Update a Node`, + Run: func(cmd *cobra.Command, args []string) { + content, err := os.ReadFile(args[2]) + if err != nil { + log.Fatal("Error when opening file: ", err) + } + node := &models.Node{} + if err := json.Unmarshal(content, node); err != nil { + log.Fatal(err) + } + functions.PrettyPrint(functions.UpdateNode(args[0], args[1], node)) + }, +} + +func init() { + rootCmd.AddCommand(nodeUpdateCmd) +} diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 3f85c49b..3fa75dfa 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -7,6 +7,7 @@ import ( "github.com/gravitl/netmaker/cli/cmd/context" "github.com/gravitl/netmaker/cli/cmd/keys" "github.com/gravitl/netmaker/cli/cmd/network" + "github.com/gravitl/netmaker/cli/cmd/node" "github.com/spf13/cobra" ) @@ -49,4 +50,5 @@ func init() { rootCmd.AddCommand(context.GetRoot()) rootCmd.AddCommand(keys.GetRoot()) rootCmd.AddCommand(acl.GetRoot()) + rootCmd.AddCommand(node.GetRoot()) } diff --git a/cli/functions/node.go b/cli/functions/node.go new file mode 100644 index 00000000..ef7bcf85 --- /dev/null +++ b/cli/functions/node.go @@ -0,0 +1,62 @@ +package functions + +import ( + "fmt" + "net/http" + + "github.com/gravitl/netmaker/models" +) + +func GetNodes(networkName ...string) *[]models.Node { + if len(networkName) == 1 { + return request[[]models.Node](http.MethodGet, "/api/nodes/"+networkName[0], nil) + } else { + return request[[]models.Node](http.MethodGet, "/api/nodes", nil) + } +} + +func GetNodeByID(networkName, nodeID string) *models.NodeGet { + return request[models.NodeGet](http.MethodGet, fmt.Sprintf("/api/nodes/%s/%s", networkName, nodeID), nil) +} + +func UpdateNode(networkName, nodeID string, node *models.Node) *models.Node { + return request[models.Node](http.MethodPut, fmt.Sprintf("/api/nodes/%s/%s", networkName, nodeID), node) +} + +func DeleteNode(networkName, nodeID string) *models.SuccessResponse { + return request[models.SuccessResponse](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s", networkName, nodeID), nil) +} + +func CreateRelay(networkName, nodeID string, relayAddresses []string) *models.Node { + return request[models.Node](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/createrelay", networkName, nodeID), &models.RelayRequest{ + NetID: networkName, + NodeID: nodeID, + RelayAddrs: relayAddresses, + }) +} + +func DeleteRelay(networkName, nodeID string) *models.Node { + return request[models.Node](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deleterelay", networkName, nodeID), nil) +} + +func CreateEgress(networkName, nodeID string, payload *models.EgressGatewayRequest) *models.Node { + return request[models.Node](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/creategateway", networkName, nodeID), payload) +} + +func DeleteEgress(networkName, nodeID string) *models.Node { + return request[models.Node](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deletegateway", networkName, nodeID), nil) +} + +func CreateIngress(networkName, nodeID string, failover bool) *models.Node { + return request[models.Node](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/createingress", networkName, nodeID), &struct { + Failover bool `json:"failover"` + }{Failover: failover}) +} + +func DeleteIngress(networkName, nodeID string) *models.Node { + return request[models.Node](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deleteingress", networkName, nodeID), nil) +} + +func UncordonNode(networkName, nodeID string) *string { + return request[string](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/approve", networkName, nodeID), nil) +} diff --git a/cli/samples/node.json b/cli/samples/node.json new file mode 100644 index 00000000..6c7c4bd8 --- /dev/null +++ b/cli/samples/node.json @@ -0,0 +1,101 @@ +{ + "id": "eda7720b-830c-4e9c-8716-9773e15da160", + "address": "", + "address6": "fd00::ffff:ffff:ffff:ffff", + "localaddress": "", + "name": "netmaker-1", + "networksettings": { + "addressrange": "", + "addressrange6": "fd00::/64", + "netid": "onaw", + "nodeslastmodified": 1668594644, + "networklastmodified": 1668594644, + "defaultinterface": "nm-onaw", + "defaultlistenport": 51821, + "nodelimit": 999999999, + "defaultpostup": "", + "defaultpostdown": "", + "defaultkeepalive": 20, + "accesskeys": [], + "allowmanualsignup": "no", + "islocal": "no", + "isipv4": "no", + "isipv6": "yes", + "ispointtosite": "no", + "localrange": "", + "defaultudpholepunch": "yes", + "defaultextclientdns": "", + "defaultmtu": 1280, + "defaultacl": "yes", + "prosettings": { + "defaultaccesslevel": 3, + "defaultusernodelimit": 0, + "defaultuserclientlimit": 0, + "allowedusers": [], + "allowedgroups": [ + "*" + ] + } + }, + "listenport": 51823, + "locallistenport": 0, + "publickey": "xuLSz/ady+E6hK36cJiCzFp5tByBjnoZid54kHp9MVY=", + "endpoint": "134.209.145.214", + "postup": "", + "postdown": "", + "allowedips": null, + "persistentkeepalive": 20, + "ishub": "no", + "accesskey": "", + "interface": "nm-onaw", + "lastmodified": 1669114997, + "expdatetime": 1968594644, + "lastpeerupdate": 1668594644, + "lastcheckin": 1669114997, + "macaddress": "netmaker-server-1", + "password": "$2a$05$CrRlIbQkuQFQBs1A4wdhX.ar90lTRV9x.4IapTZV.FBaDmVyMukIG", + "network": "onaw", + "isrelayed": "no", + "ispending": "no", + "isrelay": "no", + "isdocker": "no", + "isk8s": "no", + "isegressgateway": "no", + "isingressgateway": "no", + "egressgatewayranges": null, + "egressgatewaynatenabled": "", + "egressgatewayrequest": { + "nodeid": "", + "netid": "", + "natenabled": "", + "ranges": null, + "interface": "", + "postup": "", + "postdown": "" + }, + "relayaddrs": null, + "failovernode": "", + "ingressgatewayrange": "", + "ingressgatewayrange6": "", + "isstatic": "yes", + "udpholepunch": "no", + "dnson": "no", + "isserver": "yes", + "action": "noop", + "islocal": "no", + "localrange": "", + "ipforwarding": "yes", + "os": "linux", + "mtu": 1280, + "version": "v0.16.1", + "server": "", + "traffickeys": { + "mine": null, + "server": null + }, + "firewallinuse": "iptables", + "internetgateway": "", + "connected": "yes", + "defaultacl": "yes", + "failover": "no" + } \ No newline at end of file