mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-21 07:46:04 +08:00
commit
6b5332c6e0
28
README.md
28
README.md
|
@ -6,6 +6,28 @@
|
|||
<i>Create and control automated virtual networks.</i>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/gravitl/netmaker/releases">
|
||||
<img src="https://img.shields.io/docker/v/gravitl/netmaker?color=blue" />
|
||||
</a>
|
||||
<a href="https://discord.gg/zRb9Vfhk8A">
|
||||
<img src="https://img.shields.io/badge/community-discord-purple" />
|
||||
</a>
|
||||
<a href="https://github.com/gravitl/netmaker/graphs/contributors">
|
||||
<img src="https://img.shields.io/github/commit-activity/w/gravitl/netmaker?color=brightgreen" />
|
||||
</a>
|
||||
<a href="https://gravitl.com/resources">
|
||||
<img src="https://img.shields.io/badge/learning-resources-9cf" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=gravitlcorp">
|
||||
<img src="https://img.shields.io/twitter/follow/gravitlcorp?style=social" />
|
||||
</a>
|
||||
<a href="https://www.youtube.com/channel/UCach3lJY_xBV7rGrbUSvkZQ">
|
||||
<img src="https://img.shields.io/youtube/channel/views/UCach3lJY_xBV7rGrbUSvkZQ?style=social" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
# WireGuard® Automation from Homelab to Enterprise
|
||||
- [x] Peer-to-Peer Mesh Networks
|
||||
- [x] Site-to-Site Gateways
|
||||
|
@ -15,6 +37,7 @@
|
|||
|
||||
# Get Started in 5 Minutes
|
||||
|
||||
**For production-grade installations, visit the [Install Docs](https://netmaker.readthedocs.io/en/develop/install.html).**
|
||||
1. Get a cloud VM with Ubuntu 20.04 and a public IP.
|
||||
2. Open ports 443, 53, and 51821-51830/udp on the VM firewall and in cloud security settings.
|
||||
3. Run the script:
|
||||
|
@ -23,8 +46,6 @@
|
|||
|
||||
<img src="./docs/images/install-server.gif" width="50%" /><img src="./docs/images/visit-website.gif" width="50%" />
|
||||
|
||||
(For a more customized install, including using your own domain, head over to [the quick start guide](https://docs.netmaker.org/quick-start.html).)
|
||||
|
||||
After installing Netmaker, check out the [Walkthrough](https://itnext.io/getting-started-with-netmaker-a-wireguard-virtual-networking-platform-3d563fbd87f0) and [Getting Started](https://netmaker.readthedocs.io/en/master/getting-started.html) guide to begin setting up networks. Or, check out some of our other [Tutorials](https://gravitl.com/resources) for different use cases, including Kubernetes.
|
||||
|
||||
# Why Netmaker + WireGuard?
|
||||
|
@ -43,10 +64,9 @@ After installing Netmaker, check out the [Walkthrough](https://itnext.io/getting
|
|||
|
||||
- [Business (Subscription)](https://gravitl.com/plans/business)
|
||||
|
||||
- [Email](mailto:info@gravitl.com)
|
||||
|
||||
## Disclaimer
|
||||
[WireGuard](https://wireguard.com/) is a registered trademark of Jason A. Donenfeld.
|
||||
|
||||
## License
|
||||
|
||||
Netmaker's source code and all artifacts in this repository are freely available. All versions are published under the Server Side Public License (SSPL), version 1, which can be found here: [LICENSE.txt](./LICENSE.txt).
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.8.2
|
||||
image: gravitl/netmaker:v0.8.3
|
||||
volumes:
|
||||
- /etc/netclient/config:/etc/netclient/config
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
version: "3.4"
|
||||
|
||||
services:
|
||||
rqlite:
|
||||
container_name: rqlite
|
||||
image: rqlite/rqlite
|
||||
network_mode: host
|
||||
restart: always
|
||||
volumes:
|
||||
- sqldata:/rqlite/file/data
|
||||
netmaker:
|
||||
depends_on:
|
||||
- rqlite
|
||||
privileged: true
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.7
|
||||
volumes:
|
||||
- ./:/local
|
||||
- /etc/netclient:/etc/netclient
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
- /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
|
||||
- /run/systemd/system:/run/systemd/system
|
||||
- /etc/systemd/system:/etc/systemd/system
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_MODULE
|
||||
restart: always
|
||||
network_mode: host
|
||||
environment:
|
||||
SERVER_HOST: "SERVER_PUBLIC_IP"
|
||||
DNS_MODE: "off"
|
||||
SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
|
||||
SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
|
||||
GRPC_SSL: "on"
|
||||
SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
|
||||
SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
|
||||
API_PORT: "8081"
|
||||
GRPC_PORT: "50051"
|
||||
CLIENT_MODE: "on"
|
||||
MASTER_KEY: "REPLACE_MASTER_KEY"
|
||||
SERVER_GRPC_WIREGUARD: "off"
|
||||
CORS_ALLOWED_ORIGIN: "*"
|
||||
netmaker-ui:
|
||||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.7
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
- "8082:80"
|
||||
environment:
|
||||
BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
|
||||
volumes:
|
||||
sqldata: {}
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.8.2
|
||||
image: gravitl/netmaker:v0.8.3
|
||||
volumes:
|
||||
- /etc/netclient/config:/etc/netclient/config
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
|
|
|
@ -2,157 +2,15 @@ package controller
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var relayNode models.Node
|
||||
var err error
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed)
|
||||
|
||||
} else {
|
||||
relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
relayNode = setPeerInfo(relayNode)
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, relayNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false)
|
||||
if err == nil && relayNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == relayNode.Address {
|
||||
relayNode.Endpoint = nodepeer.Endpoint
|
||||
relayNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peers = append(peers, relayNode)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return peers, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return nil, err
|
||||
}
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
functions.PrintUserLog("", errN.Error(), 2)
|
||||
}
|
||||
for _, value := range collection {
|
||||
var node models.Node
|
||||
var peer models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if node.IsEgressGateway == "yes" { // handle egress stuff
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
}
|
||||
allow := node.IsRelayed != "yes" || !excludeRelayed
|
||||
|
||||
if node.Network == networkName && node.IsPending != "yes" && allow {
|
||||
peer = setPeerInfo(node)
|
||||
if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
|
||||
endpointstring := udppeers[node.PublicKey]
|
||||
endpointarr := strings.Split(endpointstring, ":")
|
||||
if len(endpointarr) == 2 {
|
||||
port, err := strconv.Atoi(endpointarr[1])
|
||||
if err == nil {
|
||||
peer.Endpoint = endpointarr[0]
|
||||
peer.ListenPort = int32(port)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.IsRelay == "yes" {
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func setPeerInfo(node models.Node) models.Node {
|
||||
var peer models.Node
|
||||
peer.RelayAddrs = node.RelayAddrs
|
||||
peer.IsRelay = node.IsRelay
|
||||
peer.IsRelayed = node.IsRelayed
|
||||
peer.PublicKey = node.PublicKey
|
||||
peer.Endpoint = node.Endpoint
|
||||
peer.LocalAddress = node.LocalAddress
|
||||
peer.ListenPort = node.ListenPort
|
||||
peer.AllowedIPs = node.AllowedIPs
|
||||
peer.UDPHolePunch = node.UDPHolePunch
|
||||
peer.Address = node.Address
|
||||
peer.Address6 = node.Address6
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
peer.IngressGatewayRange = node.IngressGatewayRange
|
||||
peer.IsIngressGateway = node.IsIngressGateway
|
||||
peer.IsPending = node.IsPending
|
||||
return peer
|
||||
}
|
||||
|
||||
func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
|
||||
|
||||
var peers []models.ExtPeersResponse
|
||||
records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
|
||||
for _, value := range records {
|
||||
var peer models.ExtPeersResponse
|
||||
var extClient models.ExtClient
|
||||
err = json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal([]byte(value), &extClient)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
|
||||
continue
|
||||
}
|
||||
if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
/**
|
||||
* If being deleted by server, create a record in the DELETED_NODES_TABLE for the client to find
|
||||
* If being deleted by the client, delete completely
|
||||
|
@ -183,7 +41,7 @@ func DeleteNode(key string, exterminate bool) error {
|
|||
return err
|
||||
}
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -235,93 +93,3 @@ func GetIntClient(clientid string) (models.IntClient, error) {
|
|||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func CreateNode(node models.Node, networkName string) (models.Node, error) {
|
||||
|
||||
//encrypt that password so we never see it
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
|
||||
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//set password to encrypted password
|
||||
node.Password = string(hash)
|
||||
|
||||
node.Network = networkName
|
||||
if node.Name == models.NODE_SERVER_NAME {
|
||||
node.IsServer = "yes"
|
||||
}
|
||||
if servercfg.IsDNSMode() && node.DNSOn == ""{
|
||||
node.DNSOn = "yes"
|
||||
}
|
||||
node.SetDefaults()
|
||||
node.Address, err = functions.UniqueAddress(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.Address6, err = functions.UniqueAddress6(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//Create a JWT for the node
|
||||
tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
|
||||
if tokenString == "" {
|
||||
//returnErrorResponse(w, r, errorResponse)
|
||||
return node, err
|
||||
}
|
||||
err = node.Validate(false)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
key, err := functions.GetRecordKey(node.MacAddress, node.Network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
nodebytes, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
if node.IsPending != "yes" {
|
||||
functions.DecrimentKey(node.Network, node.AccessKey)
|
||||
}
|
||||
SetNetworkNodesLastModified(node.Network)
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
|
||||
func SetNetworkServerPeers(networkName string) {
|
||||
if currentPeersList, err := serverctl.GetPeers(networkName); err == nil {
|
||||
if database.SetPeers(currentPeersList, networkName) {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "set new peers on network "+networkName, 1)
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "could not set peers on network "+networkName, 1)
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, err.Error(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func SetNetworkNodesLastModified(networkName string) error {
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.NodesLastModified = timestamp
|
||||
data, err := json.Marshal(&network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -13,20 +14,20 @@ func TestGetPeerList(t *testing.T) {
|
|||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, peers)
|
||||
})
|
||||
node := createTestNode()
|
||||
t.Run("One Node", func(t *testing.T) {
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, node.Address, peers[0].Address)
|
||||
})
|
||||
t.Run("Multiple Nodes", func(t *testing.T) {
|
||||
createnode := models.Node{PublicKey: "RM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.2", MacAddress: "02:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
CreateNode(createnode, "skynet")
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
logic.CreateNode(createnode, "skynet")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(peers), 2)
|
||||
foundNodeEndpoint := false
|
||||
|
@ -97,7 +98,7 @@ func TestCreateNode(t *testing.T) {
|
|||
createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
//err := ValidateNodeCreate("skynet", createnode)
|
||||
//assert.Nil(t, err)
|
||||
node, err := CreateNode(createnode, "skynet")
|
||||
node, err := logic.CreateNode(createnode, "skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "10.0.0.1", node.Endpoint)
|
||||
assert.Equal(t, "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", node.PublicKey)
|
||||
|
@ -113,17 +114,17 @@ func TestSetNetworkNodesLastModified(t *testing.T) {
|
|||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("InvalidNetwork", func(t *testing.T) {
|
||||
err := SetNetworkNodesLastModified("badnet")
|
||||
err := logic.SetNetworkNodesLastModified("badnet")
|
||||
assert.EqualError(t, err, "no result found")
|
||||
})
|
||||
t.Run("NetworkExists", func(t *testing.T) {
|
||||
err := SetNetworkNodesLastModified("skynet")
|
||||
err := logic.SetNetworkNodesLastModified("skynet")
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func createTestNode() models.Node {
|
||||
createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
node, _ := CreateNode(createnode, "skynet")
|
||||
node, _ := logic.CreateNode(createnode, "skynet")
|
||||
return node
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ package controller
|
|||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/txn2/txeh"
|
||||
)
|
||||
|
||||
func dnsHandlers(r *mux.Router) {
|
||||
|
@ -63,7 +63,7 @@ func GetAllDNS() ([]models.DNSEntry, error) {
|
|||
return []models.DNSEntry{}, err
|
||||
}
|
||||
for _, net := range networks {
|
||||
netdns, err := GetDNS(net.NetID)
|
||||
netdns, err := dnslogic.GetDNS(net.NetID)
|
||||
if err != nil {
|
||||
return []models.DNSEntry{}, nil
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
|
|||
var dns []models.DNSEntry
|
||||
var params = mux.Vars(r)
|
||||
|
||||
dns, err := GetCustomDNS(params["network"])
|
||||
dns, err := dnslogic.GetCustomDNS(params["network"])
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -114,65 +114,11 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(dns)
|
||||
}
|
||||
|
||||
func GetCustomDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
for _, value := range collection { // filter for entries based on network
|
||||
var entry models.DNSEntry
|
||||
if err := json.Unmarshal([]byte(value), &entry); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Network == network {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, err
|
||||
}
|
||||
|
||||
func SetDNS() error {
|
||||
hostfile := txeh.Hosts{}
|
||||
var corefilestring string
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err){
|
||||
return err
|
||||
}
|
||||
|
||||
for _, net := range networks {
|
||||
corefilestring = corefilestring + net.NetID + " "
|
||||
dns, err := GetDNS(net.NetID)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
for _, entry := range dns {
|
||||
hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
|
||||
}
|
||||
}
|
||||
if corefilestring == "" {
|
||||
corefilestring = "example.com"
|
||||
}
|
||||
|
||||
err = hostfile.SaveAs("./config/dnsconfig/netmaker.hosts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsSplitDNS() {
|
||||
err = functions.SetCorefile(corefilestring)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDNSEntryNum(domain string, network string) (int, error) {
|
||||
|
||||
num := 0
|
||||
|
||||
entries, err := GetDNS(network)
|
||||
entries, err := dnslogic.GetDNS(network)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -195,7 +141,7 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
|
|||
var dns []models.DNSEntry
|
||||
var params = mux.Vars(r)
|
||||
|
||||
dns, err := GetDNS(params["network"])
|
||||
dns, err := dnslogic.GetDNS(params["network"])
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -204,22 +150,6 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(dns)
|
||||
}
|
||||
|
||||
func GetDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
dns, err := GetNodeDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
customdns, err := GetCustomDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
dns = append(dns, customdns...)
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func createDNS(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
|
@ -241,7 +171,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -296,7 +226,7 @@ func updateDNS(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -319,7 +249,7 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
entrytext := params["domain"] + "." + params["network"]
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "deleted dns entry: "+entrytext, 1)
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -394,13 +324,13 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
|
|||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
err := SetDNS()
|
||||
err := dnslogic.SetDNS()
|
||||
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"),"pushed DNS updates to nameserver",1)
|
||||
functions.PrintUserLog(r.Header.Get("user"), "pushed DNS updates to nameserver", 1)
|
||||
json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
|
||||
}
|
||||
|
||||
|
@ -421,7 +351,7 @@ func ValidateDNSCreate(entry models.DNSEntry) error {
|
|||
err := v.Struct(entry)
|
||||
if err != nil {
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
functions.PrintUserLog("", e.Error(),1)
|
||||
functions.PrintUserLog("", e.Error(), 1)
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
@ -442,7 +372,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
|
|||
_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
|
||||
_, err := functions.GetParentNetwork(change.Network)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("",err.Error(),0)
|
||||
functions.PrintUserLog("", err.Error(), 0)
|
||||
}
|
||||
return err == nil
|
||||
})
|
||||
|
@ -465,7 +395,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
|
|||
|
||||
if err != nil {
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
functions.PrintUserLog("", e.Error(),1)
|
||||
functions.PrintUserLog("", e.Error(), 1)
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -23,7 +24,7 @@ func TestGetCustomDNS(t *testing.T) {
|
|||
deleteAllNetworks()
|
||||
createNet()
|
||||
createTestNode()
|
||||
dns, err := GetCustomDNS("skynet")
|
||||
dns, err := dnslogic.GetCustomDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
t.Log(dns)
|
||||
}
|
||||
|
@ -39,7 +40,7 @@ func TestGetDNSEntryNum(t *testing.T) {
|
|||
func TestGetDNS(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
deleteAllNetworks()
|
||||
dns, err := GetDNS("skynet")
|
||||
dns, err := dnslogic.GetDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
t.Log(dns)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
@ -273,7 +274,7 @@ func CreateExtClient(extclient models.ExtClient) error {
|
|||
if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
|
||||
return err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(extclient.Network)
|
||||
err = logic.SetNetworkNodesLastModified(extclient.Network)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
|
@ -337,8 +338,21 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func DeleteNetwork(network string) error {
|
||||
nodeCount, err := functions.GetNetworkNodeCount(network)
|
||||
nodeCount, err := functions.GetNetworkNonServerNodeCount(network)
|
||||
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
||||
// delete server nodes first then db records
|
||||
servers, err := logic.GetSortedNetworkServerNodes(network)
|
||||
if err == nil {
|
||||
for _, s := range servers {
|
||||
if err = logic.DeleteNode(s.ID, true); err != nil {
|
||||
functions.PrintUserLog("[netmaker]", "could not removed server "+s.Name+" before deleting network "+network, 2)
|
||||
} else {
|
||||
functions.PrintUserLog("[netmaker]", "removed server "+s.Name+" before deleting network "+network, 2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog("[netmaker]", "could not remove servers before deleting network "+network, 1)
|
||||
}
|
||||
return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
|
||||
}
|
||||
return errors.New("node check failed. All nodes must be deleted before deleting network")
|
||||
|
@ -465,15 +479,15 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
|
|||
var accessToken models.AccessToken
|
||||
s := servercfg.GetServerConfig()
|
||||
servervals := models.ServerConfig{
|
||||
CoreDNSAddr: s.CoreDNSAddr,
|
||||
APIConnString: s.APIConnString,
|
||||
APIHost: s.APIHost,
|
||||
APIPort: s.APIPort,
|
||||
GRPCConnString: s.GRPCConnString,
|
||||
GRPCHost: s.GRPCHost,
|
||||
GRPCPort: s.GRPCPort,
|
||||
GRPCSSL: s.GRPCSSL,
|
||||
CheckinInterval: s.CheckinInterval,
|
||||
CoreDNSAddr: s.CoreDNSAddr,
|
||||
APIConnString: s.APIConnString,
|
||||
APIHost: s.APIHost,
|
||||
APIPort: s.APIPort,
|
||||
GRPCConnString: s.GRPCConnString,
|
||||
GRPCHost: s.GRPCHost,
|
||||
GRPCPort: s.GRPCPort,
|
||||
GRPCSSL: s.GRPCSSL,
|
||||
CheckinInterval: s.CheckinInterval,
|
||||
}
|
||||
accessToken.ServerConfig = servervals
|
||||
accessToken.ClientConfig.Network = netID
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
|
@ -67,7 +68,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
|||
}
|
||||
}
|
||||
|
||||
node, err = CreateNode(node, node.Network)
|
||||
node, err = logic.CreateNode(node, node.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
|||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
}
|
||||
err = SetNetworkNodesLastModified(node.Network)
|
||||
err = logic.SetNetworkNodesLastModified(node.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -134,15 +135,15 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node.IsServer == "yes" {
|
||||
SetNetworkServerPeers(macAndNetwork[1])
|
||||
if node.IsServer == "yes" && logic.IsLeader(&node){
|
||||
logic.SetNetworkServerPeers(&node)
|
||||
}
|
||||
excludeIsRelayed := node.IsRelay != "yes"
|
||||
var relayedNode string
|
||||
if node.IsRelayed == "yes" {
|
||||
relayedNode = node.Address
|
||||
}
|
||||
peers, err := GetPeersList(macAndNetwork[1], excludeIsRelayed, relayedNode)
|
||||
peers, err := logic.GetPeersList(macAndNetwork[1], excludeIsRelayed, relayedNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -172,11 +173,10 @@ func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object)
|
|||
if len(macAndNetwork) != 2 {
|
||||
return nil, errors.New("did not receive valid node id when fetching ext peers")
|
||||
}
|
||||
peers, err := GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
|
||||
peers, err := logic.GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// cursor.Next() returns a boolean, if false there are no more items and loop will break
|
||||
var extPeers []models.Node
|
||||
for i := 0; i < len(peers); i++ {
|
||||
extPeers = append(extPeers, models.Node{
|
||||
|
|
|
@ -6,10 +6,11 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -267,7 +268,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
|||
var nodes []models.Node
|
||||
var params = mux.Vars(r)
|
||||
networkName := params["network"]
|
||||
nodes, err := GetNetworkNodes(networkName)
|
||||
nodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -279,29 +280,6 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(nodes)
|
||||
}
|
||||
|
||||
func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
//A separate function to get all nodes, not just nodes for a particular network.
|
||||
//Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
|
||||
func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -335,7 +313,7 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
|
|||
var nodes []models.Node
|
||||
var err error
|
||||
for _, networkName := range user.Networks {
|
||||
tmpNodes, err := GetNetworkNodes(networkName)
|
||||
tmpNodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -437,7 +415,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
node, err = CreateNode(node, networkName)
|
||||
node, err = logic.CreateNode(node, networkName)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -682,7 +660,7 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error)
|
|||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(netid)
|
||||
err = logic.SetNetworkNodesLastModified(netid)
|
||||
return node, err
|
||||
}
|
||||
|
||||
|
@ -733,7 +711,7 @@ func DeleteIngressGateway(networkName string, macaddress string) (models.Node, e
|
|||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(networkName)
|
||||
err = logic.SetNetworkNodesLastModified(networkName)
|
||||
return node, err
|
||||
}
|
||||
|
||||
|
@ -783,7 +761,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -81,19 +82,19 @@ func TestGetNetworkNodes(t *testing.T) {
|
|||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("BadNet", func(t *testing.T) {
|
||||
node, err := GetNetworkNodes("badnet")
|
||||
node, err := logic.GetNetworkNodes("badnet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []models.Node{}, node)
|
||||
//assert.Equal(t, "mongo: no documents in result", err.Error())
|
||||
})
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
node, err := GetNetworkNodes("skynet")
|
||||
node, err := logic.GetNetworkNodes("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []models.Node{}, node)
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
createTestNode()
|
||||
node, err := GetNetworkNodes("skynet")
|
||||
node, err := logic.GetNetworkNodes("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, []models.Node(nil), node)
|
||||
})
|
||||
|
|
|
@ -72,6 +72,21 @@ func CreateRelay(relay models.RelayRequest) (models.Node, error) {
|
|||
return node, nil
|
||||
}
|
||||
|
||||
func deleteRelay(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
nodeMac := params["macaddress"]
|
||||
netid := params["network"]
|
||||
node, err := DeleteRelay(netid, nodeMac)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
}
|
||||
|
||||
func SetRelayedNodes(yesOrno string, networkName string, addrs []string) error {
|
||||
|
||||
collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
|
@ -125,21 +140,6 @@ func UpdateRelay(network string, oldAddrs []string, newAddrs []string) {
|
|||
}
|
||||
}
|
||||
|
||||
func deleteRelay(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
nodeMac := params["macaddress"]
|
||||
netid := params["network"]
|
||||
node, err := DeleteRelay(netid, nodeMac)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
}
|
||||
|
||||
func DeleteRelay(network, macaddress string) (models.Node, error) {
|
||||
|
||||
node, err := functions.GetNodeByMacAddress(network, macaddress)
|
||||
|
@ -171,30 +171,3 @@ func DeleteRelay(network, macaddress string) (models.Node, error) {
|
|||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
var relay models.Node
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return relay, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return relay, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
err := json.Unmarshal([]byte(value), &relay)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if relay.IsRelay == "yes" {
|
||||
for _, addr := range relay.RelayAddrs {
|
||||
if addr == relayedNodeAddr {
|
||||
return relay, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relay, errors.New("could not find relay for node " + relayedNodeAddr)
|
||||
}
|
||||
|
|
|
@ -89,17 +89,17 @@ func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
|
|||
//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
|
||||
record, err := database.FetchRecord(database.USERS_TABLE_NAME, authRequest.UserName)
|
||||
if err != nil {
|
||||
return "", errors.New("user " + authRequest.UserName + " not found")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
if err = json.Unmarshal([]byte(record), &result); err != nil {
|
||||
return "", errors.New("user " + authRequest.UserName + " not found")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
|
||||
//compare password from request to stored password in database
|
||||
//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
|
||||
//TODO: Consider a way of hashing the password client side before sending, or using certificates
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)); err != nil {
|
||||
return "", errors.New("wrong password")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
|
||||
//Create a new JWT for the node
|
||||
|
|
|
@ -219,7 +219,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
|||
authRequest.Password = "password"
|
||||
jwt, err := VerifyAuthRequest(authRequest)
|
||||
assert.Equal(t, "", jwt)
|
||||
assert.EqualError(t, err, "user admin not found")
|
||||
assert.EqualError(t, err, "incorrect credentials")
|
||||
})
|
||||
t.Run("Non-Admin", func(t *testing.T) {
|
||||
user := models.User{"nonadmin", "somepass", nil, false}
|
||||
|
@ -235,7 +235,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
|||
authRequest := models.UserAuthParams{"admin", "badpass"}
|
||||
jwt, err := VerifyAuthRequest(authRequest)
|
||||
assert.Equal(t, "", jwt)
|
||||
assert.EqualError(t, err, "wrong password")
|
||||
assert.EqualError(t, err, "incorrect credentials")
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
authRequest := models.UserAuthParams{"admin", "password"}
|
||||
|
|
104
dnslogic/dns.go
Normal file
104
dnslogic/dns.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package dnslogic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/txn2/txeh"
|
||||
)
|
||||
|
||||
func SetDNS() error {
|
||||
hostfile := txeh.Hosts{}
|
||||
var corefilestring string
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, net := range networks {
|
||||
corefilestring = corefilestring + net.NetID + " "
|
||||
dns, err := GetDNS(net.NetID)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
for _, entry := range dns {
|
||||
hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
|
||||
}
|
||||
}
|
||||
if corefilestring == "" {
|
||||
corefilestring = "example.com"
|
||||
}
|
||||
|
||||
err = hostfile.SaveAs("./config/dnsconfig/netmaker.hosts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsSplitDNS() {
|
||||
err = functions.SetCorefile(corefilestring)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
dns, err := GetNodeDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
customdns, err := GetCustomDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
dns = append(dns, customdns...)
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func GetNodeDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
for _, value := range collection {
|
||||
var entry models.DNSEntry
|
||||
var node models.Node
|
||||
if err = json.Unmarshal([]byte(value), &node); err != nil {
|
||||
continue
|
||||
}
|
||||
if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func GetCustomDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
for _, value := range collection { // filter for entries based on network
|
||||
var entry models.DNSEntry
|
||||
if err := json.Unmarshal([]byte(value), &entry); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Network == network {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, err
|
||||
}
|
|
@ -9,24 +9,16 @@ ENV GO111MODULE=auto
|
|||
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 /usr/local/go/bin/go build -ldflags="-w -s" -o netmaker main.go
|
||||
|
||||
WORKDIR /app/netclient
|
||||
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient main.go
|
||||
#second stage
|
||||
|
||||
FROM alpine:3.13.6
|
||||
# add a c lib
|
||||
RUN apk add gcompat iptables
|
||||
# set the working directory
|
||||
WORKDIR /root/
|
||||
|
||||
RUN mkdir /etc/netclient
|
||||
RUN mkdir -p /etc/netclient/config
|
||||
|
||||
COPY --from=builder /app/netmaker .
|
||||
COPY --from=builder /app/config config
|
||||
COPY --from=builder /app/netclient/netclient /etc/netclient/netclient
|
||||
|
||||
RUN chmod 0755 /etc/netclient/netclient
|
||||
|
||||
EXPOSE 8081
|
||||
EXPOSE 50051
|
||||
|
|
BIN
docs/_build/doctrees/environment.pickle
vendored
BIN
docs/_build/doctrees/environment.pickle
vendored
Binary file not shown.
BIN
docs/_build/doctrees/index.doctree
vendored
BIN
docs/_build/doctrees/index.doctree
vendored
Binary file not shown.
BIN
docs/_build/doctrees/install.doctree
vendored
Normal file
BIN
docs/_build/doctrees/install.doctree
vendored
Normal file
Binary file not shown.
BIN
docs/_build/doctrees/quick-start-nginx.doctree
vendored
BIN
docs/_build/doctrees/quick-start-nginx.doctree
vendored
Binary file not shown.
BIN
docs/_build/doctrees/quick-start.doctree
vendored
BIN
docs/_build/doctrees/quick-start.doctree
vendored
Binary file not shown.
BIN
docs/_build/doctrees/server-installation.doctree
vendored
BIN
docs/_build/doctrees/server-installation.doctree
vendored
Binary file not shown.
10
docs/_build/html/_sources/index.rst.txt
vendored
10
docs/_build/html/_sources/index.rst.txt
vendored
|
@ -48,6 +48,16 @@ A technical overview of Netmaker, including design decisions and limitations.
|
|||
|
||||
architecture
|
||||
|
||||
Install
|
||||
------------------------------------
|
||||
|
||||
Choose the right install method for you.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
install
|
||||
|
||||
Quick Start
|
||||
---------------
|
||||
|
||||
|
|
20
docs/_build/html/_sources/install.rst.txt
vendored
Normal file
20
docs/_build/html/_sources/install.rst.txt
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
=========
|
||||
Install
|
||||
=========
|
||||
|
||||
Choose the install method that makes sense for you.
|
||||
|
||||
**For most users, we recommend the** :doc:`Quick Install<./quick-start>` **guide.**
|
||||
|
||||
`Trial, PoC, Testing, and Experimenting <https://github.com/gravitl/netmaker/tree/master#get-started-in-5-minutes>`_
|
||||
|
||||
:doc:`Quick Install: for general small-to-medium use cases <./quick-start>`
|
||||
|
||||
:ref:`Kubernetes Installation <KubeInstall>`
|
||||
|
||||
:ref:`Non-Docker (from binary) Install <NoDocker>`
|
||||
|
||||
:ref:`Highly Available Installation <HAInstall>`
|
||||
|
||||
:doc:`Advanced Install Resources <./server-installation>`
|
||||
|
|
@ -161,7 +161,7 @@ Start Netmaker
|
|||
|
||||
``sudo docker-compose -f docker-compose.yml up -d``
|
||||
|
||||
navigate to dashboard.<your base domain> to see your nginx instance.
|
||||
navigate to dashboard.<your base domain> to log into the UI.
|
||||
|
||||
To troubleshoot issues, start with:
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ Caddy will create 3 subdomains with this wildcard, EX:
|
|||
|
||||
ssh root@your-host
|
||||
sudo apt-get update
|
||||
sudo apt-get -y docker docker-compose wireguard
|
||||
sudo apt-get install -y docker.io docker-compose wireguard
|
||||
|
||||
At this point you should have all the system dependencies you need.
|
||||
|
||||
|
@ -132,7 +132,7 @@ Start Netmaker
|
|||
|
||||
``sudo docker-compose up -d``
|
||||
|
||||
navigate to dashboard.<your base domain> to see your nginx instance.
|
||||
navigate to dashboard.<your base domain> to begin using Netmaker.
|
||||
|
||||
To troubleshoot issues, start with:
|
||||
|
||||
|
|
|
@ -187,6 +187,8 @@ To run without DNS, follow the :doc:`Quick Install <./quick-start>` guide, omitt
|
|||
This template is equivalent but omits CoreDNS.
|
||||
|
||||
|
||||
.. _NoDocker:
|
||||
|
||||
Linux Install without Docker
|
||||
=============================
|
||||
|
||||
|
@ -234,6 +236,8 @@ The following uses Nginx as an http server. You may alternatively use Apache or
|
|||
CoreDNS Setup
|
||||
----------------
|
||||
|
||||
.. _KubeInstall:
|
||||
|
||||
Kubernetes Install
|
||||
=======================
|
||||
|
||||
|
@ -276,7 +280,7 @@ The following instructions assume you have Netmaker running and a network you wo
|
|||
For a more detailed guide on integrating Netmaker with MicroK8s, `check out this guide <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_.
|
||||
|
||||
Nginx Reverse Proxy Setup with https
|
||||
====================================
|
||||
======================================
|
||||
|
||||
The `Swag Proxy <https://github.com/linuxserver/docker-swag>`_ makes it easy to generate a valid ssl certificate for the config bellow. Here is the `documentation <https://docs.linuxserver.io/general/swag>`_ for the installation.
|
||||
|
||||
|
@ -337,3 +341,72 @@ The following file configures Netmaker as a subdomain. This config is an adaptio
|
|||
proxy_pass_request_headers on;
|
||||
}
|
||||
}
|
||||
|
||||
.. _HAInstall:
|
||||
|
||||
Highly Available Installation
|
||||
===============================
|
||||
|
||||
For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:
|
||||
|
||||
1. A load balancer
|
||||
2. 3+ Netmaker server instances
|
||||
3. rqlite as the backing database
|
||||
|
||||
These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can `schedule a consultation here <https://gravitl.com/book>`_ .
|
||||
|
||||
The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
|
||||
|
||||
1. Load Balancer Setup
|
||||
------------------------
|
||||
|
||||
Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.
|
||||
|
||||
2. RQLite Setup
|
||||
------------------
|
||||
|
||||
RQLite is the included distributed datastore for an HA Netmaker installation. If you have a different corporate database you wish to integrate, Netmaker is easily extended to other DB's. If this is a requirement, please contact us.
|
||||
|
||||
Assuming you use Rqlite, you must run it on each Netmaker server VM, or alongside that VM as a container. Setup a config.json for database credentials (password supports BCRYPT HASHING) and mount in working directory of rqlite and specify with `-auth config.json` :
|
||||
|
||||
.. code-block::
|
||||
|
||||
[{
|
||||
"username": "netmaker",
|
||||
"password": "<YOUR_DB_PASSWORD>",
|
||||
"perms": ["all"]
|
||||
}]
|
||||
|
||||
|
||||
Once your servers are set up with rqlite, the first instance must be started normally, and then additional nodes must be added with the "join" command. For instance, here is the first server node:
|
||||
|
||||
.. code-block::
|
||||
|
||||
sudo docker run -d -p 4001:4001 -p 4002:4002 rqlite/rqlite -node-id 1 -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 -http-adv-addr 1.2.3.4:4001 -raft-adv-addr 1.2.3.4:4002 -auth config.json
|
||||
|
||||
And here is a joining node:
|
||||
|
||||
.. code-block::
|
||||
|
||||
sudo docker run -d -p 4001:4001 -p 4002:4002 rqlite/rqlite -node-id 2 -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 -http-adv-addr 2.3.4.5:4001 -raft-adv-addr 2.3.4.5:4002 -join https://netmaker:<YOUR_DB_PASSWORD>@1.2.3.4:4001
|
||||
|
||||
- reference for rqlite setup: https://github.com/rqlite/rqlite/blob/master/DOC/CLUSTER_MGMT.md#creating-a-cluster
|
||||
- reference for rqlite security: https://github.com/rqlite/rqlite/blob/master/DOC/SECURITY.md
|
||||
|
||||
Once rqlite instances have been configured, the Netmaker servers can be deployed.
|
||||
|
||||
3. Netmaker Setup
|
||||
------------------
|
||||
|
||||
Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
|
||||
|
||||
4. Other Considerations
|
||||
------------------------
|
||||
|
||||
This is enough to get a functioning HA installation of Netmaker. However, you may also want to make the Netmaker UI or the CoreDNS server HA as well. The Netmaker UI can simply be added to the same servers and load balanced appropriately. For some load balancers, you may be able to do this with CoreDNS as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
14
docs/_build/html/external-clients.html
vendored
14
docs/_build/html/external-clients.html
vendored
|
@ -275,6 +275,13 @@
|
|||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="install.html" class="md-nav__link">Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
@ -462,6 +469,13 @@
|
|||
<a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
|
|
14
docs/_build/html/genindex.html
vendored
14
docs/_build/html/genindex.html
vendored
|
@ -273,6 +273,13 @@
|
|||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="install.html" class="md-nav__link">Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
@ -460,6 +467,13 @@
|
|||
<a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
|
|
26
docs/_build/html/index.html
vendored
26
docs/_build/html/index.html
vendored
|
@ -274,6 +274,13 @@
|
|||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="install.html" class="md-nav__link">Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
@ -461,6 +468,13 @@
|
|||
<a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
|
@ -743,6 +757,8 @@
|
|||
</li>
|
||||
<li class="md-nav__item"><a href="#architecture" class="md-nav__link">Architecture</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#install" class="md-nav__link">Install</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#quick-start" class="md-nav__link">Quick Start</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#quick-start-nginx-depreciated" class="md-nav__link">Quick Start Nginx (depreciated)</a>
|
||||
|
@ -813,6 +829,15 @@
|
|||
</div>
|
||||
|
||||
|
||||
<h2 id="install">Install<a class="headerlink" href="#install" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Choose the right install method for you.</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="install.html">Install</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<h2 id="quick-start">Quick Start<a class="headerlink" href="#quick-start" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A quick start guide to getting up and running with Netmaker and WireGuard as quickly as possible.</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
|
@ -863,6 +888,7 @@
|
|||
<li class="toctree-l2"><a class="reference internal" href="server-installation.html#linux-install-without-docker">Linux Install without Docker</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="server-installation.html#kubernetes-install">Kubernetes Install</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="server-installation.html#nginx-reverse-proxy-setup-with-https">Nginx Reverse Proxy Setup with https</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="server-installation.html#highly-available-installation">Highly Available Installation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
842
docs/_build/html/install.html
vendored
Normal file
842
docs/_build/html/install.html
vendored
Normal file
|
@ -0,0 +1,842 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="lang:clipboard.copy" content="Copy to clipboard">
|
||||
<meta name="lang:clipboard.copied" content="Copied to clipboard">
|
||||
<meta name="lang:search.language" content="en">
|
||||
<meta name="lang:search.pipeline.stopwords" content="True">
|
||||
<meta name="lang:search.pipeline.trimmer" content="True">
|
||||
<meta name="lang:search.result.none" content="No matching documents">
|
||||
<meta name="lang:search.result.one" content="1 matching document">
|
||||
<meta name="lang:search.result.other" content="# matching documents">
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
|
||||
<link href="https://fonts.gstatic.com/" rel="preconnect" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,500,700|Roboto:300,400,400i,700&display=fallback" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body,
|
||||
input {
|
||||
font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
}
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre {
|
||||
font-family: "Roboto Mono", "Courier New", Courier, monospace
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="_static/stylesheets/application.css"/>
|
||||
<link rel="stylesheet" href="_static/stylesheets/application-palette.css"/>
|
||||
<link rel="stylesheet" href="_static/stylesheets/application-fixes.css"/>
|
||||
|
||||
<link rel="stylesheet" href="_static/fonts/material-icons.css"/>
|
||||
|
||||
<meta name="theme-color" content="#3f51b5">
|
||||
<script src="_static/javascripts/modernizr.js"></script>
|
||||
|
||||
|
||||
|
||||
<title>Install — Netmaker 0.8.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/material.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<link rel="author" title="About these documents" href="about.html" />
|
||||
<link rel="index" title="Index" href="genindex.html" />
|
||||
<link rel="search" title="Search" href="search.html" />
|
||||
<link rel="next" title="Quick Install" href="quick-start.html" />
|
||||
<link rel="prev" title="Architecture" href="architecture.html" />
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body dir=ltr
|
||||
data-md-color-primary=indigo data-md-color-accent=light-blue>
|
||||
|
||||
<svg class="md-svg">
|
||||
<defs data-children-count="0">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448" viewBox="0 0 416 448" id="__github"><path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19T128 352t-18.125-8.5-10.75-19T96 304t3.125-20.5 10.75-19T128 256t18.125 8.5 10.75 19T160 304zm160 0q0 10-3.125 20.5t-10.75 19T288 352t-18.125-8.5-10.75-19T256 304t3.125-20.5 10.75-19T288 256t18.125 8.5 10.75 19T320 304zm40 0q0-30-17.25-51T296 232q-10.25 0-48.75 5.25Q229.5 240 208 240t-39.25-2.75Q130.75 232 120 232q-29.5 0-46.75 21T56 304q0 22 8 38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0 37.25-1.75t35-7.375 30.5-15 20.25-25.75T360 304zm56-44q0 51.75-15.25 82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5T212 416q-19.5 0-35.5-.75t-36.875-3.125-38.125-7.5-34.25-12.875T37 371.5t-21.5-28.75Q0 312 0 260q0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25 30.875Q171.5 96 212 96q37 0 70 8 26.25-20.5 46.75-30.25T376 64q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34 99.5z"/></svg>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer">
|
||||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search">
|
||||
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
|
||||
<a href="#install" tabindex="1" class="md-skip"> Skip to content </a>
|
||||
<header class="md-header" data-md-component="header">
|
||||
<nav class="md-header-nav md-grid">
|
||||
<div class="md-flex navheader">
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
<a href="index.html" title="Netmaker 0.8.2 documentation"
|
||||
class="md-header-nav__button md-logo">
|
||||
|
||||
<i class="md-icon"></i>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
<span class="md-header-nav__topic">Netmaker Docs</span>
|
||||
<span class="md-header-nav__topic"> Install </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
<form class="md-search__form" action="search.html" method="GET" name="search">
|
||||
<input type="text" class="md-search__input" name="q" placeholder="Search"
|
||||
autocapitalize="off" autocomplete="off" spellcheck="false"
|
||||
data-md-component="query" data-md-state="active">
|
||||
<label class="md-icon md-search__icon" for="__search"></label>
|
||||
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
|
||||

|
||||
</button>
|
||||
</form>
|
||||
<div class="md-search__output">
|
||||
<div class="md-search__scrollwrap" data-md-scrollfix>
|
||||
<div class="md-search-result" data-md-component="result">
|
||||
<div class="md-search-result__meta">
|
||||
Type to start searching
|
||||
</div>
|
||||
<ol class="md-search-result__list"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
<div class="md-header-nav__source">
|
||||
<a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="28" height="28">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
Netmaker
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="_static/javascripts/version_dropdown.js"></script>
|
||||
<script>
|
||||
var json_loc = ""versions.json"",
|
||||
target_loc = "../",
|
||||
text = "Versions";
|
||||
$( document ).ready( add_version_dropdown(json_loc, target_loc, text));
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="md-container">
|
||||
|
||||
|
||||
|
||||
<nav class="md-tabs" data-md-component="tabs">
|
||||
<div class="md-tabs__inner md-grid">
|
||||
<ul class="md-tabs__list">
|
||||
<li class="md-tabs__item"><a href="index.html" class="md-tabs__link">Netmaker 0.8.2 documentation</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<main class="md-main">
|
||||
<div class="md-main__inner md-grid" data-md-component="container">
|
||||
|
||||
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
<nav class="md-nav md-nav--primary" data-md-level="0">
|
||||
<label class="md-nav__title md-nav__title--site" for="__drawer">
|
||||
<a href="index.html" title="Netmaker 0.8.2 documentation" class="md-nav__button md-logo">
|
||||
|
||||
<i class="md-icon"></i>
|
||||
|
||||
</a>
|
||||
<a href="index.html"
|
||||
title="Netmaker 0.8.2 documentation">Netmaker Docs</a>
|
||||
</label>
|
||||
<div class="md-nav__source">
|
||||
<a href="https://github.com/gravitl/netmaker/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="28" height="28">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
Netmaker
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="about.html" class="md-nav__link">About</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="about.html#what-is-netmaker" class="md-nav__link">What is Netmaker?</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="about.html#how-does-netmaker-work" class="md-nav__link">How Does Netmaker Work?</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="about.html#use-cases-for-netmaker" class="md-nav__link">Use Cases for Netmaker</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html" class="md-nav__link">Architecture</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html#core-concepts" class="md-nav__link">Core Concepts</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html#components" class="md-nav__link">Components</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html#technical-process" class="md-nav__link">Technical Process</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html#compatible-systems-for-netclient" class="md-nav__link">Compatible Systems for Netclient</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="architecture.html#limitations" class="md-nav__link">Limitations</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc"> Install </label>
|
||||
|
||||
<a href="#" class="md-nav__link md-nav__link--active">Install</a>
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary">
|
||||
<ul class="md-nav__list" data-md-scrollfix="">
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html" class="md-nav__link">Quick Install</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#introduction" class="md-nav__link">Introduction</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#prerequisites" class="md-nav__link">0. Prerequisites</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#prepare-dns" class="md-nav__link">1. Prepare DNS</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#open-firewall" class="md-nav__link">3. Open Firewall</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html" class="md-nav__link">Getting Started</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html#setup" class="md-nav__link">Setup</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html#deploy-nodes" class="md-nav__link">Deploy Nodes</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html#manage-nodes" class="md-nav__link">Manage Nodes</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html#uninstalling-the-netclient" class="md-nav__link">Uninstalling the netclient</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="getting-started.html#uninstalling-netmaker" class="md-nav__link">Uninstalling Netmaker</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html" class="md-nav__link">Install with Nginx (depreciated)</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html#introduction" class="md-nav__link">0. Introduction</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html#prerequisites" class="md-nav__link">1. Prerequisites</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html#install-dependencies" class="md-nav__link">2. Install Dependencies</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html#prepare-vm" class="md-nav__link">3. Prepare VM</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="quick-start-nginx.html#install-netmaker" class="md-nav__link">4. Install Netmaker</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html" class="md-nav__link">Advanced Server Installation</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#system-compatibility" class="md-nav__link">System Compatibility</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#server-configuration-reference" class="md-nav__link">Server Configuration Reference</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#dns-mode-setup" class="md-nav__link">DNS Mode Setup</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#docker-compose-install" class="md-nav__link">Docker Compose Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#linux-install-without-docker" class="md-nav__link">Linux Install without Docker</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#kubernetes-install" class="md-nav__link">Kubernetes Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html" class="md-nav__link">Client Installation</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#introduction-to-netclient" class="md-nav__link">Introduction to Netclient</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#notes-on-windows" class="md-nav__link">Notes on Windows</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#modes-and-system-compatibility" class="md-nav__link">Modes and System Compatibility</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#prerequisites" class="md-nav__link">Prerequisites</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#configuration" class="md-nav__link">Configuration</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#installation" class="md-nav__link">Installation</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="client-installation.html#managing-netclient" class="md-nav__link">Managing Netclient</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="external-clients.html" class="md-nav__link">External Clients</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="external-clients.html#introduction" class="md-nav__link">Introduction</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="external-clients.html#configuring-an-ingress-gateway" class="md-nav__link">Configuring an Ingress Gateway</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="external-clients.html#adding-clients-to-a-gateway" class="md-nav__link">Adding Clients to a Gateway</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="external-clients.html#configuring-dns-for-ext-clients-optional" class="md-nav__link">Configuring DNS for Ext Clients (OPTIONAL)</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="usage.html" class="md-nav__link">Using Netmaker</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="usage.html#external-tutorials" class="md-nav__link">External Tutorials</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="api.html" class="md-nav__link">API Reference</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="api.html#api-usage" class="md-nav__link">API Usage</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="api.html#authentication" class="md-nav__link">Authentication</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="api.html#format-of-calls-for-curl" class="md-nav__link">Format of Calls for Curl</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="api.html#api-documentation" class="md-nav__link">API Documentation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html" class="md-nav__link">Troubleshooting</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html#common-issues" class="md-nav__link">Common Issues</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html#server" class="md-nav__link">Server</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html#ui" class="md-nav__link">UI</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html#netclient" class="md-nav__link">Netclient</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="troubleshoot.html#coredns" class="md-nav__link">CoreDNS</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="support.html" class="md-nav__link">Support</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="support.html#faq" class="md-nav__link">FAQ</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="support.html#contact" class="md-nav__link">Contact</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html" class="md-nav__link">Code of Conduct</a>
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#our-pledge" class="md-nav__link">Our Pledge</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#our-standards" class="md-nav__link">Our Standards</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#our-responsibilities" class="md-nav__link">Our Responsibilities</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#scope" class="md-nav__link">Scope</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#enforcement" class="md-nav__link">Enforcement</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="conduct.html#attribution" class="md-nav__link">Attribution</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="license.html" class="md-nav__link">License</a>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
<nav class="md-nav md-nav--secondary">
|
||||
<ul class="md-nav__list" data-md-scrollfix="">
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="md-content">
|
||||
<article class="md-content__inner md-typeset" role="main">
|
||||
|
||||
|
||||
<h1 id="install--page-root">Install<a class="headerlink" href="#install--page-root" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Choose the install method that makes sense for you.</p>
|
||||
<p><strong>For most users, we recommend the</strong> <a class="reference internal" href="quick-start.html"><span class="doc">Quick Install</span></a> <strong>guide.</strong></p>
|
||||
<p><a class="reference external" href="https://github.com/gravitl/netmaker/tree/master#get-started-in-5-minutes">Trial, PoC, Testing, and Experimenting</a></p>
|
||||
<p><a class="reference internal" href="quick-start.html"><span class="doc">Quick Install: for general small-to-medium use cases</span></a></p>
|
||||
<p><a class="reference internal" href="server-installation.html#kubeinstall"><span class="std std-ref">Kubernetes Installation</span></a></p>
|
||||
<p><a class="reference internal" href="server-installation.html#nodocker"><span class="std std-ref">Non-Docker (from binary) Install</span></a></p>
|
||||
<p><a class="reference internal" href="server-installation.html#hainstall"><span class="std std-ref">Highly Available Installation</span></a></p>
|
||||
<p><a class="reference internal" href="server-installation.html"><span class="doc">Advanced Install Resources</span></a></p>
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<footer class="md-footer">
|
||||
<div class="md-footer-nav">
|
||||
<nav class="md-footer-nav__inner md-grid">
|
||||
|
||||
<a href="architecture.html" title="Architecture"
|
||||
class="md-flex md-footer-nav__link md-footer-nav__link--prev"
|
||||
rel="prev">
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
|
||||
<span class="md-flex__ellipsis">
|
||||
<span
|
||||
class="md-footer-nav__direction"> Previous </span> Architecture </span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<a href="quick-start.html" title="Quick Install"
|
||||
class="md-flex md-footer-nav__link md-footer-nav__link--next"
|
||||
rel="next">
|
||||
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"><span
|
||||
class="md-flex__ellipsis"> <span
|
||||
class="md-footer-nav__direction"> Next </span> Quick Install </span>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink"><i
|
||||
class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
|
||||
</div>
|
||||
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
<div class="md-footer-copyright">
|
||||
<div class="md-footer-copyright__highlight">
|
||||
© Copyright 2021, Alex Feiszli.
|
||||
|
||||
</div>
|
||||
Created using
|
||||
<a href="http://www.sphinx-doc.org/">Sphinx</a> 4.0.2.
|
||||
and
|
||||
<a href="https://github.com/bashtage/sphinx-material/">Material for
|
||||
Sphinx</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="_static/javascripts/application.js"></script>
|
||||
<script>app.initialize({version: "1.0.4", url: {base: ".."}})</script>
|
||||
</body>
|
||||
</html>
|
BIN
docs/_build/html/objects.inv
vendored
BIN
docs/_build/html/objects.inv
vendored
Binary file not shown.
2
docs/_build/html/quick-start-nginx.html
vendored
2
docs/_build/html/quick-start-nginx.html
vendored
|
@ -973,7 +973,7 @@
|
|||
|
||||
<h3 id="start-netmaker">Start Netmaker<a class="headerlink" href="#start-netmaker" title="Permalink to this headline">¶</a></h3>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">docker-compose</span> <span class="pre">-f</span> <span class="pre">docker-compose.yml</span> <span class="pre">up</span> <span class="pre">-d</span></code></p>
|
||||
<p>navigate to dashboard.<your base domain> to see your nginx instance.</p>
|
||||
<p>navigate to dashboard.<your base domain> to log into the UI.</p>
|
||||
<p>To troubleshoot issues, start with:</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">logs</span> <span class="pre">netmaker</span></code></p>
|
||||
<p>Or check out the <a class="reference internal" href="troubleshoot.html"><span class="doc">troubleshoooting docs</span></a>.</p>
|
||||
|
|
4
docs/_build/html/quick-start.html
vendored
4
docs/_build/html/quick-start.html
vendored
|
@ -852,7 +852,7 @@
|
|||
<h2 id="install-dependencies">2. Install Dependencies<a class="headerlink" href="#install-dependencies" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ssh</span> <span class="n">root</span><span class="nd">@your</span><span class="o">-</span><span class="n">host</span>
|
||||
<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">update</span>
|
||||
<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="o">-</span><span class="n">y</span> <span class="n">docker</span> <span class="n">docker</span><span class="o">-</span><span class="n">compose</span> <span class="n">wireguard</span>
|
||||
<span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="o">-</span><span class="n">y</span> <span class="n">docker</span><span class="o">.</span><span class="n">io</span> <span class="n">docker</span><span class="o">-</span><span class="n">compose</span> <span class="n">wireguard</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>At this point you should have all the system dependencies you need.</p>
|
||||
|
@ -912,7 +912,7 @@
|
|||
|
||||
<h3 id="start-netmaker">Start Netmaker<a class="headerlink" href="#start-netmaker" title="Permalink to this headline">¶</a></h3>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">docker-compose</span> <span class="pre">up</span> <span class="pre">-d</span></code></p>
|
||||
<p>navigate to dashboard.<your base domain> to see your nginx instance.</p>
|
||||
<p>navigate to dashboard.<your base domain> to begin using Netmaker.</p>
|
||||
<p>To troubleshoot issues, start with:</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">logs</span> <span class="pre">netmaker</span></code></p>
|
||||
<p>Or check out the <a class="reference internal" href="troubleshoot.html"><span class="doc">troubleshoooting docs</span></a>.</p>
|
||||
|
|
14
docs/_build/html/search.html
vendored
14
docs/_build/html/search.html
vendored
|
@ -279,6 +279,13 @@
|
|||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="install.html" class="md-nav__link">Install</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
@ -466,6 +473,13 @@
|
|||
<a href="server-installation.html#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="server-installation.html#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
|
|
2
docs/_build/html/searchindex.js
vendored
2
docs/_build/html/searchindex.js
vendored
File diff suppressed because one or more lines are too long
83
docs/_build/html/server-installation.html
vendored
83
docs/_build/html/server-installation.html
vendored
|
@ -466,6 +466,18 @@
|
|||
</nav>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a><nav class="md-nav">
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#id1" class="md-nav__link">2. RQLite Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#other-considerations" class="md-nav__link">4. Other Considerations</a>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</li>
|
||||
|
@ -520,6 +532,13 @@
|
|||
<a href="#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
|
||||
|
||||
</li>
|
||||
<li class="md-nav__item">
|
||||
|
||||
|
||||
<a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a>
|
||||
|
||||
|
||||
</li></ul>
|
||||
|
||||
</li>
|
||||
|
@ -841,6 +860,18 @@
|
|||
</nav>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#nginx-reverse-proxy-setup-with-https" class="md-nav__link">Nginx Reverse Proxy Setup with https</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#highly-available-installation" class="md-nav__link">Highly Available Installation</a><nav class="md-nav">
|
||||
<ul class="md-nav__list">
|
||||
<li class="md-nav__item"><a href="#load-balancer-setup" class="md-nav__link">1. Load Balancer Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#id1" class="md-nav__link">2. RQLite Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#netmaker-setup" class="md-nav__link">3. Netmaker Setup</a>
|
||||
</li>
|
||||
<li class="md-nav__item"><a href="#other-considerations" class="md-nav__link">4. Other Considerations</a>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</li>
|
||||
|
@ -1072,7 +1103,7 @@ docker-compose up -d`
|
|||
|
||||
|
||||
|
||||
<h2 id="linux-install-without-docker">Linux Install without Docker<a class="headerlink" href="#linux-install-without-docker" title="Permalink to this headline">¶</a></h2>
|
||||
<span id="nodocker"></span><h2 id="linux-install-without-docker">Linux Install without Docker<a class="headerlink" href="#linux-install-without-docker" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Most systems support Docker, but some do not. In such environments, there are many options for installing Netmaker. Netmaker is available as a binary file, and there is a zip file of the Netmaker UI static HTML on GitHub. Beyond the UI and Server, you need to install MongoDB and CoreDNS (optional).</p>
|
||||
<p>To start, we recommend following the Nginx instructions in the <a class="reference internal" href="quick-start.html"><span class="doc">Quick Install</span></a> guide to enable SSL for your environment.</p>
|
||||
<p>Once this is enabled and configured for a domain, you can continue with the below. The recommended server runs Ubuntu 20.04.</p>
|
||||
|
@ -1118,7 +1149,7 @@ docker-compose up -d`
|
|||
|
||||
|
||||
|
||||
<h2 id="kubernetes-install">Kubernetes Install<a class="headerlink" href="#kubernetes-install" title="Permalink to this headline">¶</a></h2>
|
||||
<span id="kubeinstall"></span><h2 id="kubernetes-install">Kubernetes Install<a class="headerlink" href="#kubernetes-install" title="Permalink to this headline">¶</a></h2>
|
||||
|
||||
<h3 id="server-install">Server Install<a class="headerlink" href="#server-install" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This template assumes your cluster uses Nginx for ingress with valid wildcard certificates. If using an ingress controller other than Nginx (ex: Traefik), you will need to manually modify the Ingress entries in this template to match your environment.</p>
|
||||
|
@ -1206,6 +1237,54 @@ kubectl apply -f netclient-template.yaml
|
|||
</div>
|
||||
|
||||
|
||||
<span id="hainstall"></span><h2 id="highly-available-installation">Highly Available Installation<a class="headerlink" href="#highly-available-installation" title="Permalink to this headline">¶</a></h2>
|
||||
<p>For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>A load balancer</p></li>
|
||||
<li><p>3+ Netmaker server instances</p></li>
|
||||
<li><p>rqlite as the backing database</p></li>
|
||||
</ol>
|
||||
<p>These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can <a class="reference external" href="https://gravitl.com/book">schedule a consultation here</a> .</p>
|
||||
<p>The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.</p>
|
||||
|
||||
<h3 id="load-balancer-setup">1. Load Balancer Setup<a class="headerlink" href="#load-balancer-setup" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.</p>
|
||||
|
||||
|
||||
<h3 id="id1">2. RQLite Setup<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
|
||||
<p>RQLite is the included distributed datastore for an HA Netmaker installation. If you have a different corporate database you wish to integrate, Netmaker is easily extended to other DB’s. If this is a requirement, please contact us.</p>
|
||||
<p>Assuming you use Rqlite, you must run it on each Netmaker server VM, or alongside that VM as a container. Setup a config.json for database credentials (password supports BCRYPT HASHING) and mount in working directory of rqlite and specify with <cite>-auth config.json</cite> :</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[{</span>
|
||||
<span class="s2">"username"</span><span class="p">:</span> <span class="s2">"netmaker"</span><span class="p">,</span>
|
||||
<span class="s2">"password"</span><span class="p">:</span> <span class="s2">"<YOUR_DB_PASSWORD>"</span><span class="p">,</span>
|
||||
<span class="s2">"perms"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"all"</span><span class="p">]</span>
|
||||
<span class="p">}]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Once your servers are set up with rqlite, the first instance must be started normally, and then additional nodes must be added with the “join” command. For instance, here is the first server node:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">docker</span> <span class="n">run</span> <span class="o">-</span><span class="n">d</span> <span class="o">-</span><span class="n">p</span> <span class="mi">4001</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">p</span> <span class="mi">4002</span><span class="p">:</span><span class="mi">4002</span> <span class="n">rqlite</span><span class="o">/</span><span class="n">rqlite</span> <span class="o">-</span><span class="n">node</span><span class="o">-</span><span class="nb">id</span> <span class="mi">1</span> <span class="o">-</span><span class="n">http</span><span class="o">-</span><span class="n">addr</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">raft</span><span class="o">-</span><span class="n">addr</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span><span class="p">:</span><span class="mi">4002</span> <span class="o">-</span><span class="n">http</span><span class="o">-</span><span class="n">adv</span><span class="o">-</span><span class="n">addr</span> <span class="mf">1.2</span><span class="o">.</span><span class="mf">3.4</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">raft</span><span class="o">-</span><span class="n">adv</span><span class="o">-</span><span class="n">addr</span> <span class="mf">1.2</span><span class="o">.</span><span class="mf">3.4</span><span class="p">:</span><span class="mi">4002</span> <span class="o">-</span><span class="n">auth</span> <span class="n">config</span><span class="o">.</span><span class="n">json</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And here is a joining node:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">docker</span> <span class="n">run</span> <span class="o">-</span><span class="n">d</span> <span class="o">-</span><span class="n">p</span> <span class="mi">4001</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">p</span> <span class="mi">4002</span><span class="p">:</span><span class="mi">4002</span> <span class="n">rqlite</span><span class="o">/</span><span class="n">rqlite</span> <span class="o">-</span><span class="n">node</span><span class="o">-</span><span class="nb">id</span> <span class="mi">2</span> <span class="o">-</span><span class="n">http</span><span class="o">-</span><span class="n">addr</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">raft</span><span class="o">-</span><span class="n">addr</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span><span class="p">:</span><span class="mi">4002</span> <span class="o">-</span><span class="n">http</span><span class="o">-</span><span class="n">adv</span><span class="o">-</span><span class="n">addr</span> <span class="mf">2.3</span><span class="o">.</span><span class="mf">4.5</span><span class="p">:</span><span class="mi">4001</span> <span class="o">-</span><span class="n">raft</span><span class="o">-</span><span class="n">adv</span><span class="o">-</span><span class="n">addr</span> <span class="mf">2.3</span><span class="o">.</span><span class="mf">4.5</span><span class="p">:</span><span class="mi">4002</span> <span class="o">-</span><span class="n">join</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">netmaker</span><span class="p">:</span><span class="o"><</span><span class="n">YOUR_DB_PASSWORD</span><span class="o">></span><span class="nd">@1</span><span class="o">.</span><span class="mf">2.3</span><span class="o">.</span><span class="mi">4</span><span class="p">:</span><span class="mi">4001</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>reference for rqlite setup: <a class="reference external" href="https://github.com/rqlite/rqlite/blob/master/DOC/CLUSTER_MGMT.md#creating-a-cluster">https://github.com/rqlite/rqlite/blob/master/DOC/CLUSTER_MGMT.md#creating-a-cluster</a></p></li>
|
||||
<li><p>reference for rqlite security: <a class="reference external" href="https://github.com/rqlite/rqlite/blob/master/DOC/SECURITY.md">https://github.com/rqlite/rqlite/blob/master/DOC/SECURITY.md</a></p></li>
|
||||
</ul>
|
||||
<p>Once rqlite instances have been configured, the Netmaker servers can be deployed.</p>
|
||||
|
||||
|
||||
<h3 id="netmaker-setup">3. Netmaker Setup<a class="headerlink" href="#netmaker-setup" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.</p>
|
||||
|
||||
|
||||
<h3 id="other-considerations">4. Other Considerations<a class="headerlink" href="#other-considerations" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This is enough to get a functioning HA installation of Netmaker. However, you may also want to make the Netmaker UI or the CoreDNS server HA as well. The Netmaker UI can simply be added to the same servers and load balanced appropriately. For some load balancers, you may be able to do this with CoreDNS as well.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
|
|
@ -22,7 +22,7 @@ copyright = '2021, Alex Feiszli'
|
|||
author = 'Alex Feiszli'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.8.2'
|
||||
release = '0.8.3'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
@ -48,6 +48,16 @@ A technical overview of Netmaker, including design decisions and limitations.
|
|||
|
||||
architecture
|
||||
|
||||
Install
|
||||
------------------------------------
|
||||
|
||||
Choose the right install method for you.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
install
|
||||
|
||||
Quick Start
|
||||
---------------
|
||||
|
||||
|
|
20
docs/install.rst
Normal file
20
docs/install.rst
Normal file
|
@ -0,0 +1,20 @@
|
|||
=========
|
||||
Install
|
||||
=========
|
||||
|
||||
Choose the install method that makes sense for you.
|
||||
|
||||
**For most users, we recommend the** :doc:`Quick Install<./quick-start>` **guide.**
|
||||
|
||||
`Trial, PoC, Testing, and Experimenting <https://github.com/gravitl/netmaker/tree/master#get-started-in-5-minutes>`_
|
||||
|
||||
:doc:`Quick Install: for general small-to-medium use cases <./quick-start>`
|
||||
|
||||
:ref:`Kubernetes Installation <KubeInstall>`
|
||||
|
||||
:ref:`Non-Docker (from binary) Install <NoDocker>`
|
||||
|
||||
:ref:`Highly Available Installation <HAInstall>`
|
||||
|
||||
:doc:`Advanced Install Resources <./server-installation>`
|
||||
|
|
@ -62,7 +62,7 @@ Caddy will create 3 subdomains with this wildcard, EX:
|
|||
|
||||
ssh root@your-host
|
||||
sudo apt-get update
|
||||
sudo apt-get -y docker docker-compose wireguard
|
||||
sudo apt-get install -y docker.io docker-compose wireguard
|
||||
|
||||
At this point you should have all the system dependencies you need.
|
||||
|
||||
|
|
|
@ -187,6 +187,8 @@ To run without DNS, follow the :doc:`Quick Install <./quick-start>` guide, omitt
|
|||
This template is equivalent but omits CoreDNS.
|
||||
|
||||
|
||||
.. _NoDocker:
|
||||
|
||||
Linux Install without Docker
|
||||
=============================
|
||||
|
||||
|
@ -234,6 +236,8 @@ The following uses Nginx as an http server. You may alternatively use Apache or
|
|||
CoreDNS Setup
|
||||
----------------
|
||||
|
||||
.. _KubeInstall:
|
||||
|
||||
Kubernetes Install
|
||||
=======================
|
||||
|
||||
|
@ -276,7 +280,7 @@ The following instructions assume you have Netmaker running and a network you wo
|
|||
For a more detailed guide on integrating Netmaker with MicroK8s, `check out this guide <https://itnext.io/how-to-deploy-a-cross-cloud-kubernetes-cluster-with-built-in-disaster-recovery-bbce27fcc9d7>`_.
|
||||
|
||||
Nginx Reverse Proxy Setup with https
|
||||
====================================
|
||||
======================================
|
||||
|
||||
The `Swag Proxy <https://github.com/linuxserver/docker-swag>`_ makes it easy to generate a valid ssl certificate for the config bellow. Here is the `documentation <https://docs.linuxserver.io/general/swag>`_ for the installation.
|
||||
|
||||
|
@ -337,3 +341,72 @@ The following file configures Netmaker as a subdomain. This config is an adaptio
|
|||
proxy_pass_request_headers on;
|
||||
}
|
||||
}
|
||||
|
||||
.. _HAInstall:
|
||||
|
||||
Highly Available Installation
|
||||
===============================
|
||||
|
||||
For an enterprise Netmaker installation, you will need a server that is highly available, to ensure redundant WireGuard routing when any server goes down. To do this, you will need:
|
||||
|
||||
1. A load balancer
|
||||
2. 3+ Netmaker server instances
|
||||
3. rqlite as the backing database
|
||||
|
||||
These documents outline general HA installation guidelines. Netmaker is highly customizable to meet a wide range of enterprise environments. If you would like support with an enterprise-grade Netmaker installation, you can `schedule a consultation here <https://gravitl.com/book>`_ .
|
||||
|
||||
The main consideration here is how to configure rqlite. Most other settings and procedures match the standardized way of making applications HA: Load balancing to multiple instances, and sharing a DB. In our case, the DB (rqlite) is distributed, making HA data more easily achievable.
|
||||
|
||||
1. Load Balancer Setup
|
||||
------------------------
|
||||
|
||||
Your load balancer of choice will send requests to the Netmaker servers. Setup is similar to the various guides we have created for Nginx, Caddy, and Traefik. SSL certificates must also be configured and handled by the LB.
|
||||
|
||||
2. RQLite Setup
|
||||
------------------
|
||||
|
||||
RQLite is the included distributed datastore for an HA Netmaker installation. If you have a different corporate database you wish to integrate, Netmaker is easily extended to other DB's. If this is a requirement, please contact us.
|
||||
|
||||
Assuming you use Rqlite, you must run it on each Netmaker server VM, or alongside that VM as a container. Setup a config.json for database credentials (password supports BCRYPT HASHING) and mount in working directory of rqlite and specify with `-auth config.json` :
|
||||
|
||||
.. code-block::
|
||||
|
||||
[{
|
||||
"username": "netmaker",
|
||||
"password": "<YOUR_DB_PASSWORD>",
|
||||
"perms": ["all"]
|
||||
}]
|
||||
|
||||
|
||||
Once your servers are set up with rqlite, the first instance must be started normally, and then additional nodes must be added with the "join" command. For instance, here is the first server node:
|
||||
|
||||
.. code-block::
|
||||
|
||||
sudo docker run -d -p 4001:4001 -p 4002:4002 rqlite/rqlite -node-id 1 -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 -http-adv-addr 1.2.3.4:4001 -raft-adv-addr 1.2.3.4:4002 -auth config.json
|
||||
|
||||
And here is a joining node:
|
||||
|
||||
.. code-block::
|
||||
|
||||
sudo docker run -d -p 4001:4001 -p 4002:4002 rqlite/rqlite -node-id 2 -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 -http-adv-addr 2.3.4.5:4001 -raft-adv-addr 2.3.4.5:4002 -join https://netmaker:<YOUR_DB_PASSWORD>@1.2.3.4:4001
|
||||
|
||||
- reference for rqlite setup: https://github.com/rqlite/rqlite/blob/master/DOC/CLUSTER_MGMT.md#creating-a-cluster
|
||||
- reference for rqlite security: https://github.com/rqlite/rqlite/blob/master/DOC/SECURITY.md
|
||||
|
||||
Once rqlite instances have been configured, the Netmaker servers can be deployed.
|
||||
|
||||
3. Netmaker Setup
|
||||
------------------
|
||||
|
||||
Netmaker will be started on each node with default settings, except with DATABASE=rqlite and SQL_CONN set appropriately to reach the local rqlite instance. Rqlite will maintain consistency with each Netmaker backend.
|
||||
|
||||
4. Other Considerations
|
||||
------------------------
|
||||
|
||||
This is enough to get a functioning HA installation of Netmaker. However, you may also want to make the Netmaker UI or the CoreDNS server HA as well. The Netmaker UI can simply be added to the same servers and load balanced appropriately. For some load balancers, you may be able to do this with CoreDNS as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,11 +20,6 @@ import (
|
|||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
func CheckEndpoint(endpoint string) bool {
|
||||
endpointarr := strings.Split(endpoint, ":")
|
||||
return len(endpointarr) == 2
|
||||
}
|
||||
|
||||
func PrintUserLog(username string, message string, loglevel int) {
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() != 0 {
|
||||
|
@ -103,9 +98,9 @@ func CreateServerToken(netID string) (string, error) {
|
|||
} else {
|
||||
log.Println("server on linux")
|
||||
servervals = models.ServerConfig{
|
||||
APIConnString: "127.0.0.1:" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
APIConnString: "127.0.0.1:" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
CheckinInterval: servercfg.GetCheckinInterval(),
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +375,7 @@ func IsMacAddressUnique(macaddress string, networkName string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func GetNetworkNodeCount(networkName string) (int, error) {
|
||||
func GetNetworkNonServerNodeCount(networkName string) (int, error) {
|
||||
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
count := 0
|
||||
|
@ -392,7 +387,7 @@ func GetNetworkNodeCount(networkName string) (int, error) {
|
|||
if err = json.Unmarshal([]byte(value), &node); err != nil {
|
||||
return count, err
|
||||
} else {
|
||||
if node.Network == networkName {
|
||||
if node.Network == networkName && node.IsServer != "yes" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
@ -491,12 +486,6 @@ func IsIpCIDR(host string) bool {
|
|||
return ip != nil && ipnet != nil
|
||||
}
|
||||
|
||||
//This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
|
||||
func IsBase64(s string) bool {
|
||||
_, err := base64.StdEncoding.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
//This checks to make sure a network name is valid.
|
||||
//Switch to REGEX?
|
||||
func NameInNetworkCharSet(name string) bool {
|
||||
|
|
38
logic/extpeers.go
Normal file
38
logic/extpeers.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
|
||||
|
||||
var peers []models.ExtPeersResponse
|
||||
records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
|
||||
for _, value := range records {
|
||||
var peer models.ExtPeersResponse
|
||||
var extClient models.ExtClient
|
||||
err = json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal([]byte(value), &extClient)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
|
||||
continue
|
||||
}
|
||||
if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
88
logic/nodes.go
Normal file
88
logic/nodes.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetSortedNetworkServerNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network && node.IsServer == "yes" {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
sort.Sort(models.NodesArray(nodes))
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetPeers(node models.Node) ([]models.Node, error) {
|
||||
if node.IsServer == "yes" && IsLeader(&node) {
|
||||
SetNetworkServerPeers(&node)
|
||||
}
|
||||
excludeIsRelayed := node.IsRelay != "yes"
|
||||
var relayedNode string
|
||||
if node.IsRelayed == "yes" {
|
||||
relayedNode = node.Address
|
||||
}
|
||||
peers, err := GetPeersList(node.Network, excludeIsRelayed, relayedNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
func IsLeader(node *models.Node) bool {
|
||||
nodes, err := GetSortedNetworkServerNodes(node.Network)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("[netmaker]", "ERROR: COULD NOT RETRIEVE SERVER NODES. THIS WILL BREAK HOLE PUNCHING.", 0)
|
||||
return false
|
||||
}
|
||||
for _, n := range nodes {
|
||||
if n.LastModified > time.Now().Add(-1*time.Minute).Unix() {
|
||||
return n.Address == node.Address
|
||||
}
|
||||
}
|
||||
return len(nodes) <= 1 || nodes[1].Address == node.Address
|
||||
}
|
285
logic/util.go
Normal file
285
logic/util.go
Normal file
|
@ -0,0 +1,285 @@
|
|||
// package for logicing client and server code
|
||||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"encoding/base64"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/relay"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
//This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
|
||||
func IsBase64(s string) bool {
|
||||
_, err := base64.StdEncoding.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CheckEndpoint(endpoint string) bool {
|
||||
endpointarr := strings.Split(endpoint, ":")
|
||||
return len(endpointarr) == 2
|
||||
}
|
||||
|
||||
func SetNetworkServerPeers(node *models.Node) {
|
||||
if currentPeersList, err := GetSystemPeers(node); err == nil {
|
||||
if database.SetPeers(currentPeersList, node.Network) {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "set new peers on network "+node.Network, 1)
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "could not set peers on network "+node.Network, 1)
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, err.Error(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func DeleteNode(key string, exterminate bool) error {
|
||||
var err error
|
||||
if !exterminate {
|
||||
args := strings.Split(key, "###")
|
||||
node, err := GetNode(args[0], args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.Action = models.NODE_DELETE
|
||||
nodedata, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
}
|
||||
}
|
||||
if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsDNSMode() {
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
func CreateNode(node models.Node, networkName string) (models.Node, error) {
|
||||
|
||||
//encrypt that password so we never see it
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
|
||||
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//set password to encrypted password
|
||||
node.Password = string(hash)
|
||||
|
||||
node.Network = networkName
|
||||
if node.Name == models.NODE_SERVER_NAME {
|
||||
node.IsServer = "yes"
|
||||
}
|
||||
if servercfg.IsDNSMode() && node.DNSOn == "" {
|
||||
node.DNSOn = "yes"
|
||||
}
|
||||
node.SetDefaults()
|
||||
node.Address, err = functions.UniqueAddress(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.Address6, err = functions.UniqueAddress6(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//Create a JWT for the node
|
||||
tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
|
||||
if tokenString == "" {
|
||||
//returnErrorResponse(w, r, errorResponse)
|
||||
return node, err
|
||||
}
|
||||
err = node.Validate(false)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
key, err := functions.GetRecordKey(node.MacAddress, node.Network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
nodebytes, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
if node.IsPending != "yes" {
|
||||
functions.DecrimentKey(node.Network, node.AccessKey)
|
||||
}
|
||||
SetNetworkNodesLastModified(node.Network)
|
||||
if servercfg.IsDNSMode() {
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
|
||||
func SetNetworkNodesLastModified(networkName string) error {
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.NodesLastModified = timestamp
|
||||
data, err := json.Marshal(&network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetNode(macaddress string, network string) (models.Node, error) {
|
||||
var node models.Node
|
||||
|
||||
key, err := functions.GetRecordKey(macaddress, network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
|
||||
if err != nil {
|
||||
if data == "" {
|
||||
data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
|
||||
err = json.Unmarshal([]byte(data), &node)
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(data), &node); err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.SetDefaults()
|
||||
|
||||
return node, err
|
||||
}
|
||||
|
||||
func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return peers, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return nil, err
|
||||
}
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
functions.PrintUserLog("", errN.Error(), 2)
|
||||
}
|
||||
for _, value := range collection {
|
||||
var node models.Node
|
||||
var peer models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if node.IsEgressGateway == "yes" { // handle egress stuff
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
}
|
||||
allow := node.IsRelayed != "yes" || !excludeRelayed
|
||||
|
||||
if node.Network == networkName && node.IsPending != "yes" && allow {
|
||||
peer = setPeerInfo(node)
|
||||
if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
|
||||
endpointstring := udppeers[node.PublicKey]
|
||||
endpointarr := strings.Split(endpointstring, ":")
|
||||
if len(endpointarr) == 2 {
|
||||
port, err := strconv.Atoi(endpointarr[1])
|
||||
if err == nil {
|
||||
peer.Endpoint = endpointarr[0]
|
||||
peer.ListenPort = int32(port)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.IsRelay == "yes" {
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var relayNode models.Node
|
||||
var err error
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed)
|
||||
|
||||
} else {
|
||||
relayNode, err = relay.GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
relayNode = setPeerInfo(relayNode)
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, relayNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false)
|
||||
if err == nil && relayNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == relayNode.Address {
|
||||
relayNode.Endpoint = nodepeer.Endpoint
|
||||
relayNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peers = append(peers, relayNode)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func setPeerInfo(node models.Node) models.Node {
|
||||
var peer models.Node
|
||||
peer.RelayAddrs = node.RelayAddrs
|
||||
peer.IsRelay = node.IsRelay
|
||||
peer.IsServer = node.IsServer
|
||||
peer.IsRelayed = node.IsRelayed
|
||||
peer.PublicKey = node.PublicKey
|
||||
peer.Endpoint = node.Endpoint
|
||||
peer.LocalAddress = node.LocalAddress
|
||||
peer.ListenPort = node.ListenPort
|
||||
peer.AllowedIPs = node.AllowedIPs
|
||||
peer.UDPHolePunch = node.UDPHolePunch
|
||||
peer.Address = node.Address
|
||||
peer.Address6 = node.Address6
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
peer.IngressGatewayRange = node.IngressGatewayRange
|
||||
peer.IsIngressGateway = node.IsIngressGateway
|
||||
peer.IsPending = node.IsPending
|
||||
return peer
|
||||
}
|
25
logic/wireguard.go
Normal file
25
logic/wireguard.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
func GetSystemPeers(node *models.Node) (map[string]string, error) {
|
||||
peers := make(map[string]string)
|
||||
|
||||
client, err := wgctrl.New()
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
device, err := client.Device(node.Interface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, peer := range device.Peers {
|
||||
if IsBase64(peer.PublicKey.String()) && peer.Endpoint != nil && CheckEndpoint(peer.Endpoint.String()) {
|
||||
peers[peer.PublicKey.String()] = peer.Endpoint.String()
|
||||
}
|
||||
}
|
||||
return peers, nil
|
||||
}
|
7
main.go
7
main.go
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
controller "github.com/gravitl/netmaker/controllers"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
|
@ -81,14 +82,13 @@ func startControllers() {
|
|||
go runGRPC(&waitnetwork)
|
||||
}
|
||||
|
||||
// Run the client in goroutine locally if CLIENT_MODE is "contained"
|
||||
if servercfg.IsClientMode() == "contained" {
|
||||
if servercfg.IsClientMode() == "on" {
|
||||
waitnetwork.Add(1)
|
||||
go runClient(&waitnetwork)
|
||||
}
|
||||
|
||||
if servercfg.IsDNSMode() {
|
||||
err := controller.SetDNS()
|
||||
err := dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
log.Println("error occurred initializing DNS:", err)
|
||||
}
|
||||
|
@ -115,7 +115,6 @@ func startControllers() {
|
|||
|
||||
func runClient(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
log.Println("CLIENT_MODE running as contained")
|
||||
go func() {
|
||||
for {
|
||||
if err := serverctl.HandleContainedClient(); err != nil {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -76,6 +76,18 @@ type Node struct {
|
|||
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
|
||||
}
|
||||
|
||||
type NodesArray []Node
|
||||
|
||||
func (a NodesArray) Len() int { return len(a) }
|
||||
func (a NodesArray) Less(i, j int) bool { return isLess(a[i].Address, a[j].Address) }
|
||||
func (a NodesArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
func isLess(ipA string, ipB string) bool {
|
||||
ipNetA := net.ParseIP(ipA)
|
||||
ipNetB := net.ParseIP(ipB)
|
||||
return bytes.Compare(ipNetA, ipNetB) < 0
|
||||
}
|
||||
|
||||
func (node *Node) SetDefaultMTU() {
|
||||
if node.MTU == 0 {
|
||||
node.MTU = 1280
|
||||
|
@ -263,9 +275,12 @@ func (node *Node) SetDefaults() {
|
|||
}
|
||||
}
|
||||
// == Parent Network settings ==
|
||||
node.CheckInInterval = parentNetwork.DefaultCheckInInterval
|
||||
node.IsDualStack = parentNetwork.IsDualStack
|
||||
node.MTU = parentNetwork.DefaultMTU
|
||||
if node.IsDualStack == "" {
|
||||
node.IsDualStack = parentNetwork.IsDualStack
|
||||
}
|
||||
if node.MTU == 0 {
|
||||
node.MTU = parentNetwork.DefaultMTU
|
||||
}
|
||||
// == node defaults if not set by parent ==
|
||||
node.SetIPForwardingDefault()
|
||||
node.SetDNSOnDefault()
|
||||
|
@ -535,9 +550,9 @@ func GetAllNodes() ([]Node, error) {
|
|||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetID(macaddress string, network string) (string, error) {
|
||||
if macaddress == "" || network == "" {
|
||||
func (node *Node) GetID() (string, error) {
|
||||
if node.MacAddress == "" || node.Network == "" {
|
||||
return "", errors.New("unable to get record key")
|
||||
}
|
||||
return macaddress + "###" + network, nil
|
||||
return node.MacAddress + "###" + node.Network, nil
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ func Join(cfg config.ClientConfig, privateKey string) error {
|
|||
|
||||
func getWindowsInterval() int {
|
||||
interval := 15
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return interval
|
||||
}
|
||||
|
@ -90,12 +90,13 @@ func RunUserspaceDaemon() {
|
|||
|
||||
func CheckIn(cfg config.ClientConfig) error {
|
||||
var err error
|
||||
|
||||
if cfg.Network == "" {
|
||||
ncutils.PrintLog("required, '-n', exiting", 0)
|
||||
os.Exit(1)
|
||||
} else if cfg.Network == "all" {
|
||||
ncutils.PrintLog("running checkin for all networks", 1)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting", 1)
|
||||
return err
|
||||
|
@ -138,7 +139,7 @@ func Push(cfg config.ClientConfig) error {
|
|||
var err error
|
||||
if cfg.Network == "all" || ncutils.IsWindows() {
|
||||
ncutils.PrintLog("pushing config to server for all networks.", 0)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting.", 0)
|
||||
return err
|
||||
|
@ -164,7 +165,7 @@ func Pull(cfg config.ClientConfig) error {
|
|||
var err error
|
||||
if cfg.Network == "all" {
|
||||
ncutils.PrintLog("No network selected. Running Pull for all networks.", 0)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Error retrieving networks. Exiting.", 1)
|
||||
return err
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
|
@ -136,7 +139,6 @@ func CheckConfig(cliconf config.ClientConfig) error {
|
|||
if newNode.IsPending == "yes" {
|
||||
return errors.New("node is pending")
|
||||
}
|
||||
|
||||
actionCompleted := checkNodeActions(newNode, network, servercfg, ¤tNode, cfg)
|
||||
if actionCompleted == models.NODE_DELETE {
|
||||
return errors.New("node has been removed")
|
||||
|
@ -164,32 +166,40 @@ func Pull(network string, manual bool) (*models.Node, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient := nodepb.NewNodeServiceClient(conn)
|
||||
var resNode models.Node // just need to fill this with either server calls or client calls
|
||||
var ctx context.Context
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient := nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: node.MacAddress + "###" + node.Network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resNode models.Node
|
||||
if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
|
||||
return nil, err
|
||||
req := &nodepb.Object{
|
||||
Data: node.MacAddress + "###" + node.Network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // handle server side read
|
||||
resNode, err = logic.GetNode(node.MacAddress, node.Network)
|
||||
if err != nil && !ncutils.IsEmptyRecord(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// ensure that the OS never changes
|
||||
resNode.OS = runtime.GOOS
|
||||
|
@ -211,14 +221,20 @@ func Pull(network string, manual bool) (*models.Node, error) {
|
|||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
if resNode.IsServer != "yes" {
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
} else { // handle server side update
|
||||
if err = resNode.Update(&resNode); err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err = wireguard.SetWGConfig(network, true); err != nil {
|
||||
|
@ -244,54 +260,60 @@ func Push(network string) error {
|
|||
postnode := cfg.Node
|
||||
// always set the OS on client
|
||||
postnode.OS = runtime.GOOS
|
||||
var header metadata.MD
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
if postnode.IsPending != "yes" {
|
||||
privateKey, err := wireguard.RetrievePrivKey(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privateKeyWG, err := wgtypes.ParseKey(privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if postnode.PublicKey != privateKeyWG.PublicKey().String() {
|
||||
postnode.PublicKey = privateKeyWG.PublicKey().String()
|
||||
}
|
||||
}
|
||||
postnode.SetLastCheckIn()
|
||||
nodeData, err := json.Marshal(&postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(data.Data), &postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
if postnode.IsServer != "yes" { // handle client side
|
||||
var header metadata.MD
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
if postnode.IsPending != "yes" {
|
||||
privateKey, err := wireguard.RetrievePrivKey(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privateKeyWG, err := wgtypes.ParseKey(privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if postnode.PublicKey != privateKeyWG.PublicKey().String() {
|
||||
postnode.PublicKey = privateKeyWG.PublicKey().String()
|
||||
}
|
||||
}
|
||||
nodeData, err := json.Marshal(&postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(data.Data), &postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = postnode.Update(&postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = config.ModConfig(&postnode)
|
||||
return err
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
"strings"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
|
@ -138,7 +138,7 @@ func GetNode(network string) models.Node {
|
|||
}
|
||||
|
||||
func Uninstall() error {
|
||||
networks, err := GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("unable to retrieve networks: "+err.Error(), 1)
|
||||
ncutils.PrintLog("continuing uninstall without leaving networks", 1)
|
||||
|
@ -163,7 +163,6 @@ func Uninstall() error {
|
|||
}
|
||||
|
||||
func LeaveNetwork(network string) error {
|
||||
//need to implement checkin on server side
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -171,19 +170,20 @@ func LeaveNetwork(network string) error {
|
|||
servercfg := cfg.Server
|
||||
node := cfg.Node
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
|
||||
} else {
|
||||
if node.IsServer != "yes" {
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Printf("Failed to authenticate: %v", err)
|
||||
} else {
|
||||
} else { // handle client side
|
||||
node.SetID()
|
||||
var header metadata.MD
|
||||
_, err = wcclient.DeleteNode(
|
||||
|
@ -200,6 +200,13 @@ func LeaveNetwork(network string) error {
|
|||
ncutils.PrintLog("removed machine from "+node.Network+" network on remote server", 1)
|
||||
}
|
||||
}
|
||||
} else { // handle server side
|
||||
node.SetID()
|
||||
if err = logic.DeleteNode(node.ID, true); err != nil {
|
||||
ncutils.PrintLog("error removing server on network "+node.Network, 1)
|
||||
} else {
|
||||
ncutils.PrintLog("removed netmaker server instance on "+node.Network, 1)
|
||||
}
|
||||
}
|
||||
return RemoveLocalInstance(cfg, network)
|
||||
}
|
||||
|
@ -244,7 +251,7 @@ func DeleteInterface(ifacename string, postdown string) error {
|
|||
|
||||
func List() error {
|
||||
|
||||
networks, err := GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -267,34 +274,6 @@ func List() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func GetNetworks() ([]string, error) {
|
||||
var networks []string
|
||||
files, err := ioutil.ReadDir(ncutils.GetNetclientPathSpecific())
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), "netconfig-") {
|
||||
networkname := stringAfter(f.Name(), "netconfig-")
|
||||
networks = append(networks, networkname)
|
||||
}
|
||||
}
|
||||
return networks, err
|
||||
}
|
||||
|
||||
func stringAfter(original string, substring string) string {
|
||||
position := strings.LastIndex(original, substring)
|
||||
if position == -1 {
|
||||
return ""
|
||||
}
|
||||
adjustedPosition := position + len(substring)
|
||||
|
||||
if adjustedPosition >= len(original) {
|
||||
return ""
|
||||
}
|
||||
return original[adjustedPosition:len(original)]
|
||||
}
|
||||
|
||||
func WipeLocal(network string) error {
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
|
@ -302,7 +281,6 @@ func WipeLocal(network string) error {
|
|||
}
|
||||
nodecfg := cfg.Node
|
||||
ifacename := nodecfg.Interface
|
||||
|
||||
if ifacename != "" {
|
||||
if !ncutils.IsKernel() {
|
||||
if err = wireguard.RemoveConf(ifacename, true); err == nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"log"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
|
@ -28,7 +29,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)
|
||||
err := config.Write(&cfg, cfg.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -53,7 +53,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
cfg.Node.Endpoint = cfg.Node.LocalAddress
|
||||
} else {
|
||||
cfg.Node.Endpoint, err = ncutils.GetPublicIP()
|
||||
|
||||
}
|
||||
if err != nil || cfg.Node.Endpoint == "" {
|
||||
ncutils.Log("Error setting cfg.Node.Endpoint.")
|
||||
|
@ -82,17 +81,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
}
|
||||
}
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
// differentiate between client/server here
|
||||
var node models.Node // fill this node with appropriate calls
|
||||
postnode := &models.Node{
|
||||
Password: cfg.Node.Password,
|
||||
MacAddress: cfg.Node.MacAddress,
|
||||
|
@ -105,37 +95,63 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
LocalAddress: cfg.Node.LocalAddress,
|
||||
Interface: cfg.Node.Interface,
|
||||
PublicKey: cfg.Node.PublicKey,
|
||||
DNSOn: cfg.Node.DNSOn,
|
||||
DNSOn: cfg.Node.DNSOn,
|
||||
Name: cfg.Node.Name,
|
||||
Endpoint: cfg.Node.Endpoint,
|
||||
SaveConfig: cfg.Node.SaveConfig,
|
||||
UDPHolePunch: cfg.Node.UDPHolePunch,
|
||||
}
|
||||
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create node on server
|
||||
res, err := wcclient.CreateNode(
|
||||
context.TODO(),
|
||||
&nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ncutils.PrintLog("node created on remote server...updating configs", 1)
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
nodeData := res.Data
|
||||
var node models.Node
|
||||
if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
|
||||
return err
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create node on server
|
||||
res, err := wcclient.CreateNode(
|
||||
context.TODO(),
|
||||
&nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ncutils.PrintLog("node created on remote server...updating configs", 1)
|
||||
|
||||
nodeData := res.Data
|
||||
if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
|
||||
return err
|
||||
}
|
||||
} else { // handle server side node creation
|
||||
ncutils.Log("adding a server instance on network " + postnode.Network)
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
node, err = logic.CreateNode(*postnode, cfg.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = logic.SetNetworkNodesLastModified(node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// get free port based on returned default listen port
|
||||
|
@ -177,9 +193,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
}
|
||||
}
|
||||
|
||||
ncutils.Log("retrieving remote peers")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
|
||||
|
||||
ncutils.Log("retrieving peers")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes", node.IsServer == "yes")
|
||||
if err != nil && !ncutils.IsEmptyRecord(err) {
|
||||
ncutils.Log("failed to retrieve peers")
|
||||
return err
|
||||
|
|
|
@ -24,7 +24,7 @@ func main() {
|
|||
app := cli.NewApp()
|
||||
app.Name = "Netclient CLI"
|
||||
app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
|
||||
app.Version = "v0.8.1"
|
||||
app.Version = "v0.8.3"
|
||||
|
||||
cliFlags := []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
|
|
@ -368,3 +368,31 @@ func PrintLog(message string, loglevel int) {
|
|||
log.Println("[netclient]", message)
|
||||
}
|
||||
}
|
||||
|
||||
func GetSystemNetworks() ([]string, error) {
|
||||
var networks []string
|
||||
files, err := ioutil.ReadDir(GetNetclientPathSpecific())
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), "netconfig-") {
|
||||
networkname := stringAfter(f.Name(), "netconfig-")
|
||||
networks = append(networks, networkname)
|
||||
}
|
||||
}
|
||||
return networks, err
|
||||
}
|
||||
|
||||
func stringAfter(original string, substring string) string {
|
||||
position := strings.LastIndex(original, substring)
|
||||
if position == -1 {
|
||||
return ""
|
||||
}
|
||||
adjustedPosition := position + len(substring)
|
||||
|
||||
if adjustedPosition >= len(original) {
|
||||
return ""
|
||||
}
|
||||
return original[adjustedPosition:len(original)]
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
|
@ -40,30 +41,32 @@ func CheckIn(network string) (*models.Node, error) {
|
|||
return nil, err
|
||||
}
|
||||
node := cfg.Node
|
||||
wcclient, err := getGrpcClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// == run client action ==
|
||||
var header metadata.MD
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := wcclient.ReadNode(
|
||||
ctx,
|
||||
&nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
grpc.Header(&header),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Encountered error checking in node: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
|
||||
return nil, err
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
wcclient, err := getGrpcClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// == run client action ==
|
||||
var header metadata.MD
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := wcclient.ReadNode(
|
||||
ctx,
|
||||
&nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
grpc.Header(&header),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Encountered error checking in node: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &node, err
|
||||
}
|
||||
|
@ -116,11 +119,11 @@ func RemoveNetwork(network string) error {
|
|||
return err
|
||||
}
|
||||
*/
|
||||
func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
|
||||
|
||||
func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool, isServer bool) ([]wgtypes.PeerConfig, bool, []string, error) {
|
||||
hasGateway := false
|
||||
var gateways []string
|
||||
var peers []wgtypes.PeerConfig
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
|
||||
|
@ -132,40 +135,48 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
|||
if err != nil {
|
||||
log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
|
||||
}
|
||||
var nodes []models.Node // fill this either from server or client
|
||||
if !isServer { // set peers client side
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, hasGateway, gateways, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
|
||||
log.Println("Error unmarshaling data for peers")
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
} else { // set peers serverside
|
||||
nodes, err = logic.GetPeers(nodecfg)
|
||||
if err != nil {
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, hasGateway, gateways, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
var nodes []models.Node
|
||||
if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
|
||||
log.Println("Error unmarshaling data for peers")
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
pubkey, err := wgtypes.ParseKey(node.PublicKey)
|
||||
if err != nil {
|
||||
|
@ -240,7 +251,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
|||
}
|
||||
allowedips = append(allowedips, addr6)
|
||||
}
|
||||
if nodecfg.IsServer == "yes" {
|
||||
if nodecfg.IsServer == "yes" && !(node.IsServer == "yes"){
|
||||
peer = wgtypes.PeerConfig{
|
||||
PublicKey: pubkey,
|
||||
PersistentKeepaliveInterval: &keepaliveserver,
|
||||
|
@ -283,43 +294,62 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
|||
}
|
||||
func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
|
||||
var peers []wgtypes.PeerConfig
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
|
||||
}
|
||||
nodecfg := cfg.Node
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
var extPeers []models.Node
|
||||
if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
|
||||
return nil, err
|
||||
if nodecfg.IsServer != "yes" { // fill extPeers with client side logic
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // fill extPeers with server side logic
|
||||
tempPeers, err := logic.GetExtPeersList(nodecfg.MacAddress, nodecfg.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(tempPeers); i++ {
|
||||
extPeers = append(extPeers, models.Node{
|
||||
Address: tempPeers[i].Address,
|
||||
Address6: tempPeers[i].Address6,
|
||||
Endpoint: tempPeers[i].Endpoint,
|
||||
PublicKey: tempPeers[i].PublicKey,
|
||||
PersistentKeepalive: tempPeers[i].KeepAlive,
|
||||
ListenPort: tempPeers[i].ListenPort,
|
||||
LocalAddress: tempPeers[i].LocalAddress,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, extPeer := range extPeers {
|
||||
pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
|
||||
|
|
|
@ -267,7 +267,7 @@ func SetWGConfig(network string, peerupdate bool) error {
|
|||
servercfg := cfg.Server
|
||||
nodecfg := cfg.Node
|
||||
|
||||
peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes", nodecfg.IsServer == "yes")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
167
old-docs/API.md
167
old-docs/API.md
|
@ -1,167 +0,0 @@
|
|||
# API Reference Doc
|
||||
|
||||
## GENERAL
|
||||
|
||||
Most actions that can be performed via API can be performed via UI. We recommend managing your networks using our official netmaker-ui project. That said, Netmaker is API based, and all functions can also be achieved via API calls. If you feel the need to work with Netmaker via API, we've provided some documentation below to help guide you.
|
||||
|
||||
#### Authentication
|
||||
In general, API calls must be authenticated via a header of the format `-H "Authorization: Bearer <YOUR_SECRET_KEY>"` There are two methods of obtaining YOUR_SECRET_KEY:
|
||||
1. Using the masterkey. By default, this value is "secret key," but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [general usage](./USAGE.md) documentation for more details.
|
||||
2. Using a JWT recieved for a node. This can be retrieved by calling the `/api/nodes/<network>/authenticate` endpoint, as documented below.
|
||||
|
||||
#### Format
|
||||
In general, requests will take the format of `curl -H "Authorization: Bearer <YOUR_SECRET_KEY>" -H 'Content-Type: application/json' localhost:8081/api/path/to/endpoint`
|
||||
|
||||
## NETWORKS
|
||||
|
||||
**Get All Networks:** `/api/networks`, `GET`
|
||||
|
||||
**Create Network:** `/api/network`, `POST`
|
||||
|
||||
**Get Network:** `/api/networks/{network id}`, `GET`
|
||||
|
||||
**Update Network:** `/api/networks/{network id}`, `PUT`
|
||||
|
||||
**Delete Network:** `/api/networks/{network id}`, `DELETE`
|
||||
|
||||
**Cycle PublicKeys on all Nodes:** `/api/networks/{network id}/keyupdate`, `POST`
|
||||
|
||||
|
||||
### Network API Call Examples
|
||||
|
||||
|
||||
**Get All Networks:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks | jq`
|
||||
|
||||
**Create Network:** `curl -d '{"addressrange":"10.70.0.0/16","netid":"skynet"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks`
|
||||
|
||||
**Get Network:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet | jq`
|
||||
|
||||
**Update Network:** `curl -X PUT -d '{"displayname":"my-house"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet`
|
||||
|
||||
**Delete Network:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet`
|
||||
|
||||
**Cycle PublicKeys on all Nodes:** `curl -X POST -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keyupdate`
|
||||
|
||||
## ACCESS KEYS
|
||||
|
||||
**Get All Keys:** `/api/networks/{network id}/keys`, `GET`
|
||||
|
||||
**Create Key:** `/api/networks/{network id}/keys`, `GET`
|
||||
|
||||
**Delete Key:** `/api/networks/{network id}/keys/{keyname}`, `DELETE`
|
||||
|
||||
|
||||
### Access Key API Call Examples
|
||||
|
||||
|
||||
**Get All Keys:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys | jq`
|
||||
|
||||
**Create Key:** `curl -d '{"uses":10,"name":"mykey"}' -H "Authorization: Bearer YOUR_SECRET_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/skynet/keys`
|
||||
|
||||
**Delete Key:** `curl -X DELETE -H "Authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/networks/skynet/keys/mykey`
|
||||
|
||||
|
||||
## NODES (COMPUTERS)
|
||||
|
||||
|
||||
**Get All Nodes:** `/api/nodes`, `GET`
|
||||
|
||||
**Get Network Nodes:** `/api/nodes/{network id}`, `GET`
|
||||
|
||||
**Create Node:** `/api/nodes/{network id}`, `POST`
|
||||
|
||||
**Get Node:** `/api/nodes/{network id}/{macaddress}`, `GET`
|
||||
|
||||
**Update Node:** `/api/nodes/{network id}/{macaddress}`, `PUT`
|
||||
|
||||
**Delete Node:** `/api/nodes/{network id}/{macaddress}`, `DELETE`
|
||||
|
||||
**Check In Node:** `/api/nodes/{network id}/{macaddress}/checkin`, `POST`
|
||||
|
||||
**Create a Gateway:** `/api/nodes/{network id}/{macaddress}/creategateway`, `POST`
|
||||
|
||||
**Delete a Gateway:** `/api/nodes/{network id}/{macaddress}/deletegateway`, `DELETE`
|
||||
|
||||
**Uncordon (Approve) a Pending Node:** `/api/nodes/{network id}/{macaddress}/uncordon`, `POST`
|
||||
|
||||
**Get Last Modified Date (Last Modified Node in Network):** `/api/nodes/adm/{network id}/lastmodified`, `GET`
|
||||
|
||||
**Authenticate:** `/api/nodes/adm/{network id}/authenticate`, `POST`
|
||||
|
||||
|
||||
### Example Node API Calls
|
||||
|
||||
|
||||
**Get All Nodes:**`curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes | jq`
|
||||
|
||||
**Get Network Nodes:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet | jq`
|
||||
|
||||
**Create Node:** `curl -d '{ "endpoint": 100.200.100.200, "publickey": aorijqalrik3ajflaqrdajhkr,"macaddress": "8c:90:b5:06:f1:d9","password": "reallysecret","localaddress": "172.16.16.1","accesskey": "aA3bVG0rnItIRXDx","listenport": 6400}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet`
|
||||
|
||||
**Get Node:** `curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/nodes/skynet/{macaddress} | jq`
|
||||
|
||||
**Update Node:** `curl -X PUT -d '{"name":"laptop1"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9`
|
||||
|
||||
**Delete Node:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/skynet/nodes/8c:90:b5:06:f1:d9`
|
||||
|
||||
**Create a Gateway:** `curl -d '{ "rangestring": "172.31.0.0/16", "interface": "eth0"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/creategateway`
|
||||
|
||||
**Delete a Gateway:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/deletegateway`
|
||||
|
||||
**Approve a Pending Node:** `curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/skynet/8c:90:b5:06:f1:d9/approve`
|
||||
|
||||
**Get Last Modified Date (Last Modified Node in Network):** `curl -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/nodes/adm/skynet/lastmodified`
|
||||
|
||||
**Authenticate:** `curl -d '{"macaddress": "8c:90:b5:06:f1:d9", "password": "YOUR_PASSWORD"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
|
||||
|
||||
|
||||
## USERS
|
||||
|
||||
|
||||
**Note:** Only able to create Admin user at this time. The "user" is only used by the [user interface](https://github.com/gravitl/netmaker-ui) to authenticate the single admin user.
|
||||
|
||||
**Get User:** `/api/users/{username}`, `GET`
|
||||
|
||||
**Update User:** `/api/users/{username}`, `PUT`
|
||||
|
||||
**Delete User:** `/api/users/{username}`, `DELETE`
|
||||
|
||||
**Check for Admin User:** `/api/users/adm/hasadmin`, `GET`
|
||||
|
||||
**Create Admin User:** `/api/users/adm/createadmin`, `POST`
|
||||
|
||||
**Authenticate:** `/api/users/adm/authenticate`, `POST`
|
||||
|
||||
|
||||
### Example User API Calls
|
||||
|
||||
|
||||
**Get User:**`curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/{username} | jq`
|
||||
|
||||
**Update User:** `curl -X PUT -d '{"password":"noonewillguessthis"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
|
||||
|
||||
**Delete User:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/{username}`
|
||||
|
||||
**Check for Admin User:**`curl -H "Authorization: Bearer YOUR_SECRET_KEY" http://localhost:8081/api/users/adm/hasadmin`
|
||||
|
||||
**Create Admin User:** `curl -d '{ "username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/users/adm/createadmin`
|
||||
|
||||
**Authenticate:** `curl -d '{"username": "smartguy", "password": "YOUR_PASS"}' -H 'Content-Type: application/json' localhost:8081/api/nodes/adm/skynet/authenticate`
|
||||
|
||||
## SERVER MGMT
|
||||
|
||||
The Server Mgmt. API allows you to add and remove the server from networks.
|
||||
|
||||
**Add to Network:** `/api/server/addnetwork/{network id}`, `POST`
|
||||
|
||||
**Remove from Network:** `/api/server/removenetwork/{network id}`, `DELETE`
|
||||
|
||||
**Add to Network:** `curl -X POST -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/server/addnetwork/{network id}`
|
||||
|
||||
**Remove from Network:** `curl -X DELETE -H "authorization: Bearer YOUR_SECRET_KEY" localhost:8081/api/server/removenetwork/{network id}`
|
||||
|
||||
## FILE SERVER
|
||||
|
||||
**Get File:** `/meshclient/files/{filename}`, `GET`
|
||||
|
||||
**Example:** `curl localhost:8081/meshclient/files/meshclient`
|
|
@ -1,74 +0,0 @@
|
|||
## Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
### Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
### Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
### Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at info@gravitl.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -1,28 +0,0 @@
|
|||
# Contributing to Netmaker
|
||||
Welcome! If you're reading this, you might be wondering how to go about submitting some changes, whether those are features, bugfixes, or simple enhancements. You're in the right place. Please read below to learn more.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please read through our [code of conduct](./CODE_OF_CONDUCT.md), and when making contributions to the community, stay true to that text.
|
||||
|
||||
## Report bugs and requests [here](https://github.com/gravitl/netmaker/issues)
|
||||
We use GitHub issues to track bugs, feature requests, and enhancements. If you think there's something missing or wrong with Netmaker, let us know! Try to add the appropriate tags and describe your issue thoroughly. If it's a feature request and we like it, we'll add it to the [roadmap](ROADMAP.md)
|
||||
|
||||
## Submitting a PR
|
||||
We actively welcome contributions, and the way to do that is with a PR:
|
||||
|
||||
1. Fork the repo
|
||||
2. Create a branch from `develop` based on what you are developing. In general this will be a feature or a bugfix branch, and should have the format of feature_vX.X_mynewfeature or bugfix_vX.X_mybugfix. Check the releases to see what minor version we are currently developing.
|
||||
3. Do your thing
|
||||
4. Document thoroughly
|
||||
5. Issue a PR to `develop`
|
||||
6. Sign the CLA
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
When submitting a PR, you will be asked to sign a CLA, defined [here](https://gist.github.com/afeiszli/2f9f8133929e7d5574a9d892959d58a7). We've tried to make this as non-annoying as possible. This is adapted from the text used by the Apache Foundation in their CLA.
|
||||
|
||||
This project is evolving quickly and we may want to move to an MIT or GPL license at some point in the near future, which would be difficult without a CLA.
|
||||
|
||||
## Licensing
|
||||
Any contributions you make will be under the SSPL Software License. When you submit code changes, you understand that they will be under the same license that covers this project, defined [here](../LICENSE.txt). If you have any concerns around this, feel free to contact the maintainers.
|
|
@ -1,27 +0,0 @@
|
|||
##### https://docs.docker.com/engine/install/ubuntu/
|
||||
|
||||
## Install Docker (Ubuntu)
|
||||
|
||||
1. sudo apt-get install \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
lsb-release
|
||||
|
||||
2. curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
|
||||
3. echo \
|
||||
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
|
||||
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
|
||||
4. sudo apt-get update
|
||||
|
||||
5. sudo apt-get install docker-ce docker-ce-cli containerd.io
|
||||
|
||||
## Install Docker Compose (Ubuntu)
|
||||
|
||||
6. sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
|
||||
7. sudo chmod +x /usr/local/bin/docker-compose
|
|
@ -1,96 +0,0 @@
|
|||
# FEATURE ROADMAP
|
||||
|
||||
### 0.1
|
||||
**Server:**
|
||||
- [x] Create Networks (virtual networks)
|
||||
- [x] Allow default settings for nodes from networks
|
||||
- [x] Admin/Superuser key
|
||||
- [x] Create multiuse keys for node signup
|
||||
- [x] JWT-based auth for post-signup
|
||||
- [x] CRUD for networks
|
||||
- [x] CRUD for nodes
|
||||
- [x] Track all important info about node for networking (port, endpoints, pub key, etc)
|
||||
- [x] Timestamps for determining if nodes need updates
|
||||
|
||||
**Agent:**
|
||||
- [x] Self-installer
|
||||
- [x] Determine default settings w/o user input
|
||||
- [x] Systemd Service + timer
|
||||
- [x] Check-in functionality to retrieve updates from server
|
||||
- [x] Maintain list of up-to-date peers
|
||||
- [x] Update WG interface
|
||||
- [x] Config file for modifying node
|
||||
|
||||
### 0.2
|
||||
- [x] Separate out README into DOCS folder with the following:
|
||||
- [x] API Docs
|
||||
- [x] Usage
|
||||
- [ ] Advanced Usage
|
||||
- [x] Contributing
|
||||
- [ ] Roadmap
|
||||
- [ ] Troubleshooting
|
||||
|
||||
**Server:**
|
||||
- [x] Allow tracking multiple networks per node
|
||||
- [ ] Configure Check-in thresholds
|
||||
- [ ] Separate sign-up endpoint to allow VPN-only comms after joining network
|
||||
- [ ] Swagger Docs
|
||||
- [x] Build Out README
|
||||
- [x] Encode Server, Port, and Network into Keys
|
||||
- [ ] Switch to Unique ID for nodes instead of MacAddress
|
||||
- [x] Public Key refresh
|
||||
- [ ] Enable ipv6 addresses
|
||||
- [x] Have a "default" network created at startup
|
||||
|
||||
**Agent:**
|
||||
- [x] Test / get working on multiple linux platforms
|
||||
- [ ] Set private DNS via etc hosts (node name + ip). Make it optional flag on agent.
|
||||
- [x] Decode Server, Port, and Network from Key
|
||||
- [ ] Service ID / unit file for SystemD Service
|
||||
- [x] Allow multiple interfaces
|
||||
- [ ] Use "Check in interval" from server
|
||||
- [x] Pre-req check on machine (wg, port forwarding)
|
||||
- [ ] Enable ipv6 addresses
|
||||
|
||||
### 0.3
|
||||
**Server:**
|
||||
- [ ] Swagger Docs
|
||||
- [ ] Network/Node labels
|
||||
- [ ] "Read Only" mode for nodes (can't update their settings centrally, only read)
|
||||
- [ ] "No-GUI mode:" Similar to existing, just do more e2e testing and make sure flow makes sense
|
||||
- [ ] Let users set prefixes (node, interface)
|
||||
|
||||
**Agent:**
|
||||
- [ ] Do system calls instead of direct commands
|
||||
- [ ] Add a prompt for easy setup
|
||||
|
||||
### 0.4
|
||||
**Server:**
|
||||
- [ ] Private DNS
|
||||
- [ ] UDP Hole-Punching (via WGSD: https://github.com/jwhited/wgsd )
|
||||
- [ ] "Read Only" mode for nodes (can't update their settings centrally, only read)
|
||||
|
||||
**Agent:**
|
||||
- [ ] Do system calls instead of direct commands [this repo](https://github.com/gravitl/netmaker-ui)
|
||||
- [ ] Add a prompt for easy setup
|
||||
- [ ] Make it work as a sidecar container!!!
|
||||
|
||||
### 0.5
|
||||
**Server:**
|
||||
- [ ] Multi-user support
|
||||
- [ ] Oauth
|
||||
- [ ] public key cycling
|
||||
|
||||
### Future Considerations
|
||||
**Server:**
|
||||
- [ ] Switch to distributed protocol (RAFT, Kademlia) instead of central server
|
||||
- [ ] Load balance / fault tolerant server
|
||||
- [ ] Change DB / make more scaleable (SQL?)
|
||||
- [ ] Redis
|
||||
- [ ] Network/Node labels
|
||||
|
||||
**Agent:**
|
||||
- [ ] userspace via Docker or Golang
|
||||
- [ ] MacOS support
|
||||
- [ ] Windows support
|
||||
- [ ] Certificate-based authentication
|
|
@ -1 +0,0 @@
|
|||
# This document will cover how to set up site to site connections using netmaker
|
|
@ -1,29 +0,0 @@
|
|||
# Netmaker Troubleshooting Help
|
||||
|
||||
## Client (netclient)
|
||||
### Problem: netclient-install script not working
|
||||
### Problem: Hanging artifacts from previous install
|
||||
### Problem: Need to change access token settings
|
||||
|
||||
|
||||
### Client fails to install
|
||||
|
||||
### Cannot run install script
|
||||
|
||||
### Issue with accesstoken created by UI
|
||||
|
||||
|
||||
## Server
|
||||
### Server not added to default network
|
||||
### Global config not found
|
||||
|
||||
|
||||
|
||||
## MongoDB
|
||||
|
||||
|
||||
|
||||
## UI
|
||||
|
||||
### Incorrect backend detected. Please specify correct URL and refresh. Given: http://localhost:8081
|
||||
Solution: Front end expects a reachable address for the backend. Localhost is default. Check if server is up. If server is up, make sure you've got the right endpoint (endpoint of server. Will not be 'localhost' unless doing local testing). If server is up and endpoint is correct, check for port blockings.
|
|
@ -1,140 +0,0 @@
|
|||
# Usage
|
||||
|
||||
This guide covers advanced usage of Netmaker. If you are just looking to get started quickly, check out the Quick Start in the [README](../README.md).
|
||||
|
||||
## Server Config
|
||||
Netmaker settings can be set via Environment Variables or Config file. There are also a couple of runtime arguments that can optionally be set.
|
||||
|
||||
### Environment Variables
|
||||
**APP_ENV**: default=dev. Determines which environment file to use. Will look under config/environments/APP_ENV.yaml. For instance, you can have different environments for dev, test, and prod, and store different settinggs accordingly.
|
||||
**GRPC_PORT**: default=50051. The port for GRPC (node/client) communications
|
||||
**API_PORT**: default=8081. The port for API and UI communications
|
||||
**MASTER_KEY**: default=secretkey. The skeleton key used for authenticating with server as administrator.
|
||||
|
||||
MongoDB Connection Env Vars:
|
||||
**MONGO_USER**:default=admin
|
||||
**MONGO_HOST**:default=password
|
||||
**MONGO_PASS**:default=localhost
|
||||
**MONGO_PORTS**:default=27017
|
||||
**MONGO_OPTS**:default=/?authSource=admin
|
||||
|
||||
**BACKEND_URL**: default=nil. The address of the server. Used for setting token values for client/nodes. If not set, will run a command to retrieve the server URL.
|
||||
|
||||
### Config File
|
||||
Stored as config/environments/*.yaml. Default used is dev.yaml
|
||||
|
||||
**server**:
|
||||
- **host:** "localhost" (reachable address of this server, overriden by BACKEND_URL)
|
||||
- **apiport:** "8081" (api port, overriden by API_PORT)
|
||||
- **grpcport**: "50051" (grpc port, overridden by GRPC_PORT)
|
||||
- **masterkey**: "secretkey" (administrator server API key, overridden by MASTER_KEY)
|
||||
- **allowedorigin**: "*" (CORS policy for requests)
|
||||
- **restbackend**: true (Runs the REST server)
|
||||
- **agentbackend**: true (Runs the GRPC server)
|
||||
- **defaultnetname**: "default" (name for the default network)
|
||||
- **defaultnetrange**: "10.10.10.0/24" (range for the default network)
|
||||
- **createdefault**: true (Flag for creating the default network)
|
||||
|
||||
**mongoconn**: (see ENV values above for explanation. ENV values override.)
|
||||
- **user**: "mongoadmin"
|
||||
- **pass**: "mongopass"
|
||||
- **host**: "localhost"
|
||||
- **port**: "27017"
|
||||
- **opts**: '/?authSource=admin'
|
||||
|
||||
### Runtime Args
|
||||
|
||||
**clientmode**: (default=on) E.x.: `sudo netmaker --clientmode=off` Run the Server as a client (node) as well.
|
||||
**defaultnet**: (default=on) E.x.: `sudo netmaker --defaultnet=off` Create a default network on startup.
|
||||
|
||||
## Client Config
|
||||
|
||||
Client config files are stored under /etc/netclient per network as /etc/netclient/netconfig-< network name >
|
||||
**server:**
|
||||
address: The address:port of the server
|
||||
accesskey: The acceess key used to sign up with the server
|
||||
|
||||
**node:**
|
||||
name: a displayname for the node, e.g. "mycomputer"
|
||||
interface: the network interface name, by default something like "nm-"
|
||||
network: the netmaker network being attached to
|
||||
password: the node's hashed password. Can be changed by putting a value in here and setting "postchanges" to "true"
|
||||
macaddress: the mac address of the node
|
||||
localaddress: the local network address
|
||||
wgaddress: the wireguard private address
|
||||
roamingoff: flag to update the IP address automatically based on network changes
|
||||
islocal: whether or not this is a local or public network
|
||||
allowedips: the allowedips addresses that other nodes will recieve
|
||||
localrange: the local address range if it's a local network
|
||||
postup: post up rules for gateway nodes
|
||||
postdown: post down rules for gateway nodes
|
||||
port: the wiregard port
|
||||
keepalive: the default keepalive value between this and all other nodes
|
||||
publickey: the public key other nodes will use to access this node
|
||||
privatekey: the private key of the nodes (this field does nothing)
|
||||
endpoint: the reachable endpoint of the node for routing, either local or public.
|
||||
postchanges: either "true" or "false" (with quotes). If true, will post any changes you make to the remote server.
|
||||
|
||||
|
||||
## Non-Docker Installation
|
||||
|
||||
### MongoDB Setup
|
||||
1. Install MongoDB on your server. For Ubuntu: `sudo apt install -y mongodb`. For more advanced installation or other operating systems, see the [MongoDB documentation](https://docs.mongodb.com/manual/administration/install-community/).
|
||||
|
||||
2. Create a user:
|
||||
`mongo admin`
|
||||
> `db.createUser({ user: "mongoadmin" , pwd: "mongopass", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"]})`
|
||||
|
||||
### Server Setup
|
||||
1. **Run the install script:** sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.2/netmaker-server.sh | sh -
|
||||
2. Check status: `sudo journalctl -u netmaker`
|
||||
2. If any settings are incorrect such as host or mongo credentials, change them under /etc/netmaker/config/environments/ENV.yaml and then run `sudo systemctl restart netmaker`
|
||||
|
||||
### UI Setup
|
||||
1. **Download UI asset files:** `sudo wget -O /usr/share/nginx/html/netmaker-ui.zip https://github.com/gravitl/netmaker-ui/releases/download/latest/netmaker-ui.zip`
|
||||
|
||||
2. **Unzip:** `sudo unzip /usr/share/nginx/html/netmaker-ui.zip -d /usr/share/nginx/html`
|
||||
|
||||
3. **Copy Config to Nginx:** `sudo cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/default.conf`
|
||||
|
||||
4. **Modify Default Config Path:** `sudo sed -i 's/root \/var\/www\/html/root \/usr\/share\/nginx\/html/g' /etc/nginx/sites-available/default`
|
||||
|
||||
5. **Change Backend URL:** `sudo sh -c 'BACKEND_URL=http://<YOUR BACKEND API URL>:PORT /usr/share/nginx/html/generate_config_js.sh >/usr/share/nginx/html/config.js'`
|
||||
|
||||
6. **Start Nginx:** `sudo systemctl start nginx`
|
||||
|
||||
### Agent Setup
|
||||
|
||||
On each machine you would like to add to the network, do the following:
|
||||
|
||||
1. Confirm wireguard is installed: `sudo apt install wireguard-tools`
|
||||
2. Confirm ipv4 forwarding is enabled: `sysctl -w net.ipv4.ip_forward=1`
|
||||
3. Create a key or enable manual node signup at the network level
|
||||
4. Run the install command generated by key create: `sudo curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/v0.2/netclient-install.sh | KEY=YOUR_TOKEN sh -`
|
||||
4.a. For additional networks on the same machine, you can just run `sudo netclient -c install -t YOUR_TOKEN`
|
||||
4.b. For offline installs (no access to github), you can self-host a netclient file server on netmaker
|
||||
|
||||
This will install netclient@.service and netclient-YOUR_NET.timer in systemd, which will run periodically to call the netclient binary, which will check to see if there are any updates that it needs and update WireGuard appropriately.
|
||||
|
||||
## BUILDING
|
||||
**Back End Compilation**
|
||||
The backend can be compiled by running "go build" from the root of the repository, which will create an executable named "netmaker."
|
||||
|
||||
**Client Compilation**
|
||||
Similarly, "go build" can be run from the netclient directory to produce a netclient executable.
|
||||
|
||||
**Protoc command for GRPC Compilation:**
|
||||
Whenever making changes to grpc/node.proto, you will need to recompile the grpc. This can be achieved by running the following command from the root of the repository.
|
||||
|
||||
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative grpc/node.proto
|
||||
|
||||
**Build binary:** `go build ./`
|
||||
|
||||
|
||||
## TESTING
|
||||
|
||||
**Unit Testing**
|
||||
When making changes to Netmaker, you may wish to create nodes, networks, or keys for testing. Bash scripts have been created under the "test" directory (*.sh) which run curl commands that generate sample nodes, networks, and keys that can be used for testing purposes.
|
||||
|
||||
**Integration Testing**
|
||||
Similarly, several go scripts have been created under the test directory (*.go) to test out changes to the code base. These will be run automatically when PR's are submitted but can also be run manually using "go test."
|
37
relay/relay.go
Normal file
37
relay/relay.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package relay
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
var relay models.Node
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return relay, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return relay, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
err := json.Unmarshal([]byte(value), &relay)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if relay.IsRelay == "yes" {
|
||||
for _, addr := range relay.RelayAddrs {
|
||||
if addr == relayedNodeAddr {
|
||||
return relay, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relay, errors.New("could not find relay for node " + relayedNodeAddr)
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z "$KEY" ] && KEY=nokey;
|
||||
|
||||
wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.5.11/netclient
|
||||
chmod +x netclient
|
||||
sudo ./netclient join -t $KEY
|
||||
rm -f netclient
|
|
@ -1,60 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
[ -z "$SERVER_DOMAIN" ] && echo "Need to set SERVER_DOMAIN (format: 1.2.3.4 or mybackend.com)" && exit 1;
|
||||
|
||||
|
||||
docker volume create mongovol && docker run -d --name mongodb -v mongovol:/data/db --network host -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo --bind_ip 0.0.0.0
|
||||
|
||||
mkdir -p /etc/netmaker/config/environments
|
||||
wget -O /etc/netmaker/netmaker https://github.com/gravitl/netmaker/releases/download/latest/netmaker
|
||||
chmod +x /etc/netmaker/netmaker
|
||||
|
||||
|
||||
cat >/etc/netmaker/config/environments/dev.yaml<<EOL
|
||||
server:
|
||||
host: "$SERVER_DOMAIN"
|
||||
apiport: "8081"
|
||||
grpcport: "50051"
|
||||
masterkey: "secretkey"
|
||||
allowedorigin: "*"
|
||||
restbackend: true
|
||||
agentbackend: true
|
||||
defaultnetname: "default"
|
||||
defaultnetrange: "10.10.10.0/24"
|
||||
createdefault: true
|
||||
mongoconn:
|
||||
user: "mongoadmin"
|
||||
pass: "mongopass"
|
||||
host: "localhost"
|
||||
port: "27017"
|
||||
opts: '/?authSource=admin'
|
||||
EOL
|
||||
|
||||
cat >/etc/netmaker/config/Corefile<<EOL
|
||||
. {
|
||||
hosts /root/netmaker.hosts
|
||||
}
|
||||
EOL
|
||||
|
||||
cat >/etc/systemd/system/netmaker.service<<EOL
|
||||
[Unit]
|
||||
Description=Netmaker Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
||||
WorkingDirectory=/etc/netmaker
|
||||
ExecStart=/etc/netmaker/netmaker
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
systemctl daemon-reload
|
||||
systemctl start netmaker.service
|
||||
|
||||
|
||||
docker run -d --name netmaker-ui -p 80:80 -e BACKEND_URL="http://$SERVER_DOMAIN:8081" gravitl/netmaker-ui:v0.2
|
||||
docker run -d --name coredns --restart=always --volume=/etc/netmaker/config/:/root/ -p 52:53/udp coredns/coredns -conf /root/Corefile
|
|
@ -1,101 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
[ -z "$SERVER_DOMAIN" ] && echo "Need to set SERVER_DOMAIN (format: 1.2.3.4 or mybackend.com)" && exit 1;
|
||||
|
||||
|
||||
install() {
|
||||
|
||||
docker volume create mongovol && docker run -d --name mongodb -v mongovol:/data/db -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo
|
||||
|
||||
echo "Giving Mongo Time to Start"
|
||||
sleep 10
|
||||
echo "Installing Netmaker API"
|
||||
|
||||
mkdir -p /etc/netmaker/config/environments
|
||||
mkdir -p /etc/netmaker/config/dnsconfig
|
||||
cp ../netmaker /etc/netmaker/netmaker
|
||||
chmod +x /etc/netmaker/netmaker
|
||||
|
||||
|
||||
cat >/etc/netmaker/config/environments/dev.yaml<<EOL
|
||||
server:
|
||||
host: "$SERVER_DOMAIN"
|
||||
apiport: "8081"
|
||||
grpcport: "50051"
|
||||
masterkey: "secretkey"
|
||||
allowedorigin: "*"
|
||||
restbackend: true
|
||||
agentbackend: true
|
||||
defaultnetname: "default"
|
||||
defaultnetrange: "10.10.10.0/24"
|
||||
createdefault: true
|
||||
mongoconn:
|
||||
user: "mongoadmin"
|
||||
pass: "mongopass"
|
||||
host: "127.0.0.1"
|
||||
port: "27017"
|
||||
opts: '/?authSource=admin'
|
||||
EOL
|
||||
|
||||
cat >/etc/netmaker/config/dnsconfig/Corefile<<EOL
|
||||
. {
|
||||
hosts ./root/netmaker.hosts {
|
||||
fallthrough
|
||||
}
|
||||
forward . 8.8.8.8 8.8.4.4
|
||||
log
|
||||
}
|
||||
EOL
|
||||
|
||||
cat >/etc/systemd/system/netmaker.service<<EOL
|
||||
[Unit]
|
||||
Description=Netmaker Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
||||
WorkingDirectory=/etc/netmaker
|
||||
ExecStart=/etc/netmaker/netmaker
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
systemctl daemon-reload
|
||||
systemctl start netmaker.service
|
||||
sudo docker pull coredns/coredns
|
||||
sudo docker pull gravitl/netmaker-ui:v0.3
|
||||
|
||||
systemctl stop systemd-resolved
|
||||
systemctl disable systemd-resolved
|
||||
echo "Running CoreDNS"
|
||||
sudo docker run -d --name coredns --restart=always --volume=/etc/netmaker/config/dnsconfig/:/root/ -p 53:53/udp coredns/coredns -conf /root/Corefile
|
||||
|
||||
echo "Running UI"
|
||||
sudo docker run -d --name netmaker-ui -p 80:80 -e BACKEND_URL="http://$SERVER_DOMAIN:8081" gravitl/netmaker-ui:v0.3
|
||||
|
||||
echo "Setup Complete"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
sudo docker kill mongodb || true
|
||||
sudo docker rm mongodb || true
|
||||
sudo docker volume rm mongovol || true
|
||||
sudo docker kill coredns || true
|
||||
sudo docker rm coredns || true
|
||||
sudo docker kill netmaker-ui || true
|
||||
sudo docker rm netmaker-ui || true
|
||||
sudo netclient -c remove -n default || true
|
||||
sudo rm -rf /etc/systemd/system/netmaker.service || true
|
||||
sudo rm -rf /etc/netmaker || true
|
||||
sudo systemctl enable systemd-resolved
|
||||
sudo systemctl start systemd-resolved
|
||||
sleep 5
|
||||
sudo systemctl restart systemd-resolved
|
||||
}
|
||||
|
||||
trap cleanup ERR
|
||||
cleanup
|
||||
install
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p /etc/netmaker/config/environments
|
||||
wget -O /etc/netmaker/netmaker https://github.com/gravitl/netmaker/releases/download/latest/netmaker
|
||||
chmod +x /etc/netmaker/netmaker
|
||||
|
||||
cat >/etc/netmaker/config/environments/dev.yaml<<EOL
|
||||
server:
|
||||
host:
|
||||
apiport: "8081"
|
||||
grpcport: "50051"
|
||||
masterkey: "secretkey"
|
||||
allowedorigin: "*"
|
||||
restbackend: true
|
||||
agentbackend: true
|
||||
dnsmode: "on"
|
||||
EOL
|
||||
|
||||
cat >/etc/systemd/system/netmaker.service<<EOL
|
||||
[Unit]
|
||||
Description=Netmaker Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
||||
WorkingDirectory=/etc/netmaker
|
||||
ExecStart=/etc/netmaker/netmaker
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
systemctl daemon-reload
|
||||
systemctl start netmaker.service
|
|
@ -22,7 +22,7 @@ do
|
|||
fi
|
||||
done
|
||||
|
||||
dependencies=("docker" "docker-compose" "wireguard")
|
||||
dependencies=("docker.io" "docker-compose" "wireguard")
|
||||
|
||||
for dependency in ${dependencies[@]}; do
|
||||
is_installed=$(dpkg-query -W --showformat='${Status}\n' ${dependency} | grep "install ok installed")
|
||||
|
@ -56,6 +56,7 @@ NETMAKER_BASE_DOMAIN=nm.$(curl -s ifconfig.me | tr . -).nip.io
|
|||
COREDNS_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
||||
SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
|
||||
REPLACE_MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
|
||||
EMAIL="fake@email.com"
|
||||
|
||||
echo " domain: $NETMAKER_BASE_DOMAIN"
|
||||
echo " coredns ip: $COREDNS_IP"
|
||||
|
@ -63,112 +64,46 @@ echo " public ip: $SERVER_PUBLIC_IP"
|
|||
echo " master key: $REPLACE_MASTER_KEY"
|
||||
|
||||
|
||||
echo "creating caddyfile..."
|
||||
|
||||
cat >/root/Caddyfile<<EOL
|
||||
{
|
||||
# LetsEncrypt account
|
||||
email fake@email.com
|
||||
}
|
||||
|
||||
# Dashboard
|
||||
https://dashboard.$NETMAKER_BASE_DOMAIN {
|
||||
reverse_proxy http://127.0.0.1:8082
|
||||
}
|
||||
|
||||
# API
|
||||
https://api.$NETMAKER_BASE_DOMAIN {
|
||||
reverse_proxy http://127.0.0.1:8081
|
||||
}
|
||||
|
||||
# gRPC
|
||||
https://grpc.$NETMAKER_BASE_DOMAIN {
|
||||
reverse_proxy h2c://127.0.0.1:50051
|
||||
}
|
||||
EOL
|
||||
echo "setting caddyfile..."
|
||||
|
||||
|
||||
echo "creating docker-compose.yml..."
|
||||
wget -O /root/Caddyfile https://raw.githubusercontent.com/gravitl/netmaker/master/docker/Caddyfile
|
||||
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile
|
||||
sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile
|
||||
|
||||
cat >/root/docker-compose.yml<<EOL
|
||||
version: "3.4"
|
||||
|
||||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.8.2
|
||||
volumes:
|
||||
- /etc/netclient/config:/etc/netclient/config
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
- sqldata:/root/data
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
restart: always
|
||||
network_mode: host
|
||||
environment:
|
||||
SERVER_HOST: "$SERVER_PUBLIC_IP"
|
||||
SERVER_API_CONN_STRING: "api.$NETMAKER_BASE_DOMAIN:443"
|
||||
SERVER_GRPC_CONN_STRING: "grpc.$NETMAKER_BASE_DOMAIN:443"
|
||||
COREDNS_ADDR: "$SERVER_PUBLIC_IP"
|
||||
GRPC_SSL: "on"
|
||||
DNS_MODE: "on"
|
||||
SERVER_HTTP_HOST: "api.$NETMAKER_BASE_DOMAIN"
|
||||
SERVER_GRPC_HOST: "grpc.$NETMAKER_BASE_DOMAIN"
|
||||
API_PORT: "8081"
|
||||
GRPC_PORT: "50051"
|
||||
CLIENT_MODE: "contained"
|
||||
MASTER_KEY: "REPLACE_MASTER_KEY"
|
||||
SERVER_GRPC_WIREGUARD: "off"
|
||||
CORS_ALLOWED_ORIGIN: "*"
|
||||
DATABASE: "sqlite"
|
||||
netmaker-ui:
|
||||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.8
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
- "8082:80"
|
||||
environment:
|
||||
BACKEND_URL: "https://api.$NETMAKER_BASE_DOMAIN"
|
||||
restart: always
|
||||
coredns:
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: coredns/coredns
|
||||
command: -conf /root/dnsconfig/Corefile
|
||||
container_name: coredns
|
||||
restart: always
|
||||
ports:
|
||||
- "$COREDNS_IP:53:53/udp"
|
||||
- "$COREDNS_IP:53:53/tcp"
|
||||
volumes:
|
||||
- dnsconfig:/root/dnsconfig
|
||||
caddy:
|
||||
image: caddy:latest
|
||||
container_name: caddy
|
||||
restart: unless-stopped
|
||||
network_mode: host # Wants ports 80 and 443!
|
||||
volumes:
|
||||
- /root/Caddyfile:/etc/caddy/Caddyfile
|
||||
# - $PWD/site:/srv # you could also serve a static site in site folder
|
||||
- caddy_data:/data
|
||||
- caddy_conf:/config
|
||||
volumes:
|
||||
caddy_data: {}
|
||||
caddy_conf: {}
|
||||
sqldata: {}
|
||||
dnsconfig: {}
|
||||
EOL
|
||||
echo "setting docker-compose..."
|
||||
|
||||
wget -O /root/docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.caddy.yml
|
||||
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
|
||||
sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
|
||||
sed -i "s/COREDNS_IP/$COREDNS_IP/g" /root/docker-compose.yml
|
||||
sed -i "s/REPLACE_MASTER_KEY/$REPLACE_MASTER_KEY/g" /root/docker-compose.yml
|
||||
|
||||
echo "starting containers..."
|
||||
|
||||
docker-compose -f /root/docker-compose.yml up -d
|
||||
|
||||
sleep 5
|
||||
cat << "EOF"
|
||||
|
||||
echo "finished installing"
|
||||
|
||||
echo "visit dashboard.$NETMAKER_BASE_DOMAIN to log in"
|
||||
______ ______ ______ __ __ __ ______ __
|
||||
/\ ___\ /\ == \ /\ __ \ /\ \ / / /\ \ /\__ _\ /\ \
|
||||
\ \ \__ \ \ \ __< \ \ __ \ \ \ \'/ \ \ \ \/_/\ \/ \ \ \____
|
||||
\ \_____\ \ \_\ \_\ \ \_\ \_\ \ \__| \ \_\ \ \_\ \ \_____\
|
||||
\/_____/ \/_/ /_/ \/_/\/_/ \/_/ \/_/ \/_/ \/_____/
|
||||
|
||||
__ __ ______ ______ __ __ ______ __ __ ______ ______
|
||||
/\ "-.\ \ /\ ___\ /\__ _\ /\ "-./ \ /\ __ \ /\ \/ / /\ ___\ /\ == \
|
||||
\ \ \-. \ \ \ __\ \/_/\ \/ \ \ \-./\ \ \ \ __ \ \ \ _"-. \ \ __\ \ \ __<
|
||||
\ \_\\"\_\ \ \_____\ \ \_\ \ \_\ \ \_\ \ \_\ \_\ \ \_\ \_\ \ \_____\ \ \_\ \_\
|
||||
\/_/ \/_/ \/_____/ \/_/ \/_/ \/_/ \/_/\/_/ \/_/\/_/ \/_____/ \/_/ /_/
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
echo " finished installing"
|
||||
echo " "
|
||||
echo " visit dashboard.$NETMAKER_BASE_DOMAIN to log in"
|
||||
echo " "
|
||||
echo " "
|
|
@ -1,7 +0,0 @@
|
|||
rm -rf /etc/systemd/system/netclient-default.timer
|
||||
rm -rf /etc/systemd/system/netclient@.service
|
||||
rm -rf /etc/netclient/
|
||||
systemctl daemon-reload
|
||||
ip link del nm-default
|
||||
ip link del nm-grpc-wg
|
||||
docker-compose -f /root/netmaker/compose/docker-compose.yml down --volumes
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin.bash
|
||||
docker volume create mongovol
|
||||
docker run -d --name mongodb -v mongovol:/data/db --network host -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo --bind_ip 0.0.0.0
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
echo "Starting."
|
||||
|
||||
sudo netclient -c remove-all || true
|
||||
sudo rm -rf /usr/local/bin/netclient || true
|
||||
sudo rm -rf /etc/netclient|| true
|
||||
find /etc/systemd/system/ -name 'netclient*' -exec rm {} \;
|
||||
sudo systemctl daemon-reload || true
|
||||
|
||||
echo "Done."
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
echo "Starting."
|
||||
|
||||
sudo docker kill mongodb || true
|
||||
sudo docker rm mongodb || true
|
||||
sudo docker volume rm mongovol || true
|
||||
sudo docker volume rm `docker volume ls -q -f dangling=true` || true
|
||||
sudo docker kill coredns || true
|
||||
sudo docker rm coredns || true
|
||||
sudo docker kill netmaker-ui || true
|
||||
sudo docker rm netmaker-ui || true
|
||||
sudo netclient -c remove -n default || true
|
||||
sudo rm -rf /etc/systemd/system/netmaker.service || true
|
||||
sudo rm -rf /etc/netmaker || true
|
||||
sudo rm -rf /usr/local/bin/netclient || true
|
||||
sudo rm -rf /etc/netclient|| true
|
||||
find /etc/systemd/system/ -name 'netclient*' -exec rm {} \;
|
||||
sudo systemctl daemon-reload || true
|
||||
sudo systemctl enable systemd-resolved || true
|
||||
sudo systemctl start systemd-resolved || true
|
||||
sleep 5
|
||||
sudo systemctl restart systemd-resolved || true
|
||||
|
||||
echo "Done."
|
|
@ -74,7 +74,7 @@ func GetAPIConnString() string {
|
|||
return conn
|
||||
}
|
||||
func GetVersion() string {
|
||||
version := "0.8.1"
|
||||
version := "0.8.3"
|
||||
if config.Config.Server.Version != "" {
|
||||
version = config.Config.Server.Version
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
nccommand "github.com/gravitl/netmaker/netclient/command"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
@ -91,18 +91,8 @@ func copy(src, dst string) (int64, error) {
|
|||
}
|
||||
|
||||
func RemoveNetwork(network string) (bool, error) {
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
_, err := os.Stat(netclientPath + "/netclient")
|
||||
if err != nil {
|
||||
log.Println("could not find " + netclientPath + "/netclient")
|
||||
return false, err
|
||||
}
|
||||
_, err = ncutils.RunCmd(netclientPath+"/netclient leave -n "+network, true)
|
||||
if err == nil {
|
||||
log.Println("Server removed from network " + network)
|
||||
}
|
||||
err := nccommand.Leave(config.ClientConfig{Network: network})
|
||||
return true, err
|
||||
|
||||
}
|
||||
|
||||
func InitServerNetclient() error {
|
||||
|
@ -114,82 +104,89 @@ func InitServerNetclient() error {
|
|||
log.Println("could not find or create", netclientDir)
|
||||
return err
|
||||
}
|
||||
_, err = os.Stat(netclientDir + "/netclient")
|
||||
if os.IsNotExist(err) {
|
||||
err = InstallNetclient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = os.Chmod(netclientDir+"/netclient", 0755)
|
||||
if err != nil {
|
||||
log.Println("could not change netclient binary permissions")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func HandleContainedClient() error {
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
servernets, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
if len(servernets) > 0 {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
err := SyncNetworks(servernets)
|
||||
if err != nil && servercfg.GetVerbose() >= 1 {
|
||||
log.Printf("[server netclient] error syncing networks %s \n", err)
|
||||
}
|
||||
err = nccommand.CheckIn(config.ClientConfig{Network: "all"})
|
||||
if err != nil && servercfg.GetVerbose() >= 1 {
|
||||
log.Printf("[server netclient] error occurred %s \n", err)
|
||||
}
|
||||
if servercfg.GetVerbose() >= 3 {
|
||||
log.Println("[server netclient]", "completed a checkin call")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
checkinCMD := exec.Command(netclientPath+"/netclient", "checkin", "-n", "all")
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
checkinCMD.Stdout = os.Stdout
|
||||
}
|
||||
checkinCMD.Stderr = os.Stderr
|
||||
err := checkinCMD.Start()
|
||||
func SyncNetworks(servernets []models.Network) error {
|
||||
|
||||
localnets, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
// check networks to join
|
||||
for _, servernet := range servernets {
|
||||
exists := false
|
||||
for _, localnet := range localnets {
|
||||
if servernet.NetID == localnet {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
success, err := AddNetwork(servernet.NetID)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("network add failed for " + servernet.NetID)
|
||||
}
|
||||
log.Printf("[server] error adding network %s during sync %s \n", servernet.NetID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = checkinCMD.Wait()
|
||||
if err != nil {
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
log.Println(err)
|
||||
// check networks to leave
|
||||
for _, localnet := range localnets {
|
||||
exists := false
|
||||
for _, servernet := range servernets {
|
||||
if servernet.NetID == localnet {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
success, err := RemoveNetwork(localnet)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("network delete failed for " + localnet)
|
||||
}
|
||||
log.Printf("[server] error removing network %s during sync %s \n", localnet, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if servercfg.GetVerbose() >= 3 {
|
||||
log.Println("[server netclient]", "completed a checkin call")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddNetwork(network string) (bool, error) {
|
||||
pubip, err := servercfg.GetPublicIP()
|
||||
if err != nil {
|
||||
log.Println("could not get public IP.")
|
||||
return false, err
|
||||
}
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
|
||||
token, err := functions.CreateServerToken(network)
|
||||
if err != nil {
|
||||
log.Println("could not create server token for " + network)
|
||||
return false, err
|
||||
}
|
||||
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "executing network join: "+netclientPath+"netclient "+"join "+"-t "+token+" -name "+models.NODE_SERVER_NAME+" -endpoint "+pubip, 0)
|
||||
var joinCMD *exec.Cmd
|
||||
if servercfg.IsClientMode() == "contained" {
|
||||
joinCMD = exec.Command(netclientPath+"/netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip, "-daemon", "off", "-dnson", "no")
|
||||
} else {
|
||||
joinCMD = exec.Command(netclientPath+"/netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip)
|
||||
}
|
||||
joinCMD.Stdout = os.Stdout
|
||||
joinCMD.Stderr = os.Stderr
|
||||
err = joinCMD.Start()
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
log.Println("Waiting for join command to finish...")
|
||||
err = joinCMD.Wait()
|
||||
if err != nil {
|
||||
log.Printf("Command finished with error: %v", err)
|
||||
return false, err
|
||||
}
|
||||
err := nccommand.Join(config.ClientConfig{
|
||||
Network: network,
|
||||
Daemon: "off",
|
||||
Node: models.Node{
|
||||
Network: network,
|
||||
IsServer: "yes",
|
||||
Name: models.NODE_SERVER_NAME,
|
||||
},
|
||||
}, "")
|
||||
log.Println("Server added to network " + network)
|
||||
return true, err
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package serverctl
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
func GetPeers(networkName string) (map[string]string, error) {
|
||||
peers := make(map[string]string)
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
iface := network.DefaultInterface
|
||||
|
||||
client, err := wgctrl.New()
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
device, err := client.Device(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, peer := range device.Peers {
|
||||
if functions.IsBase64(peer.PublicKey.String()) && peer.Endpoint != nil && functions.CheckEndpoint(peer.Endpoint.String()) {
|
||||
peers[peer.PublicKey.String()] = peer.Endpoint.String()
|
||||
}
|
||||
}
|
||||
return peers, nil
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
PUBKEY="DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
|
||||
IPADDR="67.169.21.168"
|
||||
MACADDRESS="56:2a:9c:d4:e2:15"
|
||||
ACCESSKEY="secretkey"
|
||||
PASSWORD="password"
|
||||
|
||||
generate_post_json ()
|
||||
{
|
||||
cat <<EOF
|
||||
{
|
||||
"endpoint": "$IPADDR",
|
||||
"publickey": "$PUBKEY",
|
||||
"macaddress": "$MACADDRESS",
|
||||
"password": "$PASSWORD"
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
POST_JSON=$(generate_post_json)
|
||||
|
||||
echo $POST_JSON
|
||||
|
||||
curl --max-time 5.0 -d "$POST_JSON" -H 'Content-Type: application/json' -H "authorization: Bearer mastertoken" localhost:8081/api/doofusnet/nodes
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo docker kill mongodb
|
||||
sudo docker rm mongodb
|
||||
sudo docker volume rm mongovol
|
||||
|
||||
docker volume create mongovol && docker run -d --name mongodb -v mongovol:/data/db --network host -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo --bind_ip 0.0.0.0
|
|
@ -191,7 +191,7 @@ func TestAuthenticateUser(t *testing.T) {
|
|||
password: "xxxxxxx",
|
||||
code: http.StatusBadRequest,
|
||||
tokenExpected: false,
|
||||
errMessage: "Wrong Password",
|
||||
errMessage: "Incorrect Credentials",
|
||||
},
|
||||
AuthorizeTestCase{
|
||||
testname: "Valid User",
|
||||
|
|
Loading…
Reference in a new issue