mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-08 14:15:25 +08:00
commit
612832cb2f
32 changed files with 942 additions and 296 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,7 @@
|
|||
netmaker
|
||||
netclient/netclient
|
||||
netclient/files/netclient
|
||||
netclient/netclient-amd64
|
||||
netclient/netclient-arm
|
||||
netclient/netclient-arm64
|
||||
config/dnsconfig/
|
||||
|
|
|
@ -54,6 +54,7 @@ services:
|
|||
- "8082:80"
|
||||
environment:
|
||||
BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
|
||||
restart: always
|
||||
coredns:
|
||||
depends_on:
|
||||
- netmaker
|
||||
|
|
|
@ -42,7 +42,6 @@ type ServerConfig struct {
|
|||
GRPCHost string `yaml:"grpchost"`
|
||||
GRPCPort string `yaml:"grpcport"`
|
||||
GRPCSecure string `yaml:"grpcsecure"`
|
||||
DefaultNodeLimit int32 `yaml:"defaultnodelimit"`
|
||||
MasterKey string `yaml:"masterkey"`
|
||||
AllowedOrigin string `yaml:"allowedorigin"`
|
||||
RestBackend string `yaml:"restbackend"`
|
||||
|
@ -52,6 +51,11 @@ type ServerConfig struct {
|
|||
DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
|
||||
DisableDefaultNet string `yaml:"disabledefaultnet"`
|
||||
GRPCSSL string `yaml:"grpcssl"`
|
||||
Version string `yaml:"version"`
|
||||
SQLConn string `yaml:"sqlconn"`
|
||||
Platform string `yaml:"platform"`
|
||||
Database string `yaml:database`
|
||||
DefaultNodeLimit int32 `yaml:"defaultnodelimit"`
|
||||
Verbosity int32 `yaml:"verbosity"`
|
||||
}
|
||||
|
||||
|
|
|
@ -9,4 +9,6 @@ server:
|
|||
agentbackend: "" # defaults to "on" or AGENT_BACKEND (if set)
|
||||
clientmode: "" # defaults to "on" or CLIENT_MODE (if set)
|
||||
dnsmode: "" # defaults to "on" or DNS_MODE (if set)
|
||||
disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)
|
||||
sqlconn: "" # defaults to "http://" or SQL_CONN (if set)
|
||||
disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)
|
||||
version: "" # version of server
|
|
@ -58,7 +58,7 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
|
|||
func GetAllDNS() ([]models.DNSEntry, error) {
|
||||
var dns []models.DNSEntry
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil {
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return []models.DNSEntry{}, err
|
||||
}
|
||||
for _, net := range networks {
|
||||
|
@ -139,7 +139,7 @@ func SetDNS() error {
|
|||
hostfile := txeh.Hosts{}
|
||||
var corefilestring string
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil {
|
||||
if err != nil && !database.IsEmptyRecord(err){
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
err := errors.New("Networks Error")
|
||||
if networksSlice[0] == ALL_NETWORK_ACCESS {
|
||||
allnetworks, err = models.GetNetworks()
|
||||
if err != nil {
|
||||
if err != nil && !database.IsEmptyRecord(err){
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
@ -150,21 +150,6 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(allnetworks)
|
||||
}
|
||||
|
||||
func RemoveComms(networks []models.Network) []models.Network {
|
||||
var index int = 100000001
|
||||
for ind, net := range networks {
|
||||
if net.NetID == "comms" {
|
||||
index = ind
|
||||
}
|
||||
}
|
||||
if index == 100000001 {
|
||||
return networks
|
||||
}
|
||||
returnable := make([]models.Network, 0)
|
||||
returnable = append(returnable, networks[:index]...)
|
||||
return append(returnable, networks[index+1:]...)
|
||||
}
|
||||
|
||||
func ValidateNetworkUpdate(network models.Network) error {
|
||||
v := validator.New()
|
||||
|
||||
|
@ -379,13 +364,15 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
success, err := serverctl.AddNetwork(network.NetID)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("Failed to add server to network " + network.DisplayName)
|
||||
if servercfg.IsClientMode() {
|
||||
success, err := serverctl.AddNetwork(network.NetID)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("Failed to add server to network " + network.DisplayName)
|
||||
}
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"), "created network "+network.NetID, 1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"net/http"
|
||||
"github.com/gorilla/mux"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
)
|
||||
|
||||
func serverHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(true, http.HandlerFunc(addNetwork))).Methods("POST")
|
||||
r.HandleFunc("/api/server/getconfig", securityCheckServer(false, http.HandlerFunc(getConfig))).Methods("GET")
|
||||
r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(true, http.HandlerFunc(removeNetwork))).Methods("DELETE")
|
||||
r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(true, http.HandlerFunc(addNetwork))).Methods("POST")
|
||||
r.HandleFunc("/api/server/getconfig", securityCheckServer(false, http.HandlerFunc(getConfig))).Methods("GET")
|
||||
r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(true, http.HandlerFunc(removeNetwork))).Methods("DELETE")
|
||||
}
|
||||
|
||||
//Security check is middleware for every function and just checks to make sure that its the master calling
|
||||
|
@ -29,93 +30,83 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
|
|||
bearerToken := r.Header.Get("Authorization")
|
||||
|
||||
var tokenSplit = strings.Split(bearerToken, " ")
|
||||
var authToken = ""
|
||||
var authToken = ""
|
||||
if len(tokenSplit) < 2 {
|
||||
errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
|
||||
}
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
} else {
|
||||
errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
|
||||
}
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
} else {
|
||||
authToken = tokenSplit[1]
|
||||
}
|
||||
//all endpoints here require master so not as complicated
|
||||
//still might not be a good way of doing this
|
||||
user, _, isadmin, err := functions.VerifyUserToken(authToken)
|
||||
errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
|
||||
}
|
||||
if !adminonly && (err != nil || user == "") {
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
}
|
||||
if !isadmin && !authenticateMasterServer(authToken) {
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
}
|
||||
user, _, isadmin, err := functions.VerifyUserToken(authToken)
|
||||
errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
|
||||
}
|
||||
if !adminonly && (err != nil || user == "") {
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
if adminonly && !isadmin && !authenticateMasterServer(authToken) {
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
//Consider a more secure way of setting master key
|
||||
func authenticateMasterServer(tokenString string) bool {
|
||||
if tokenString == servercfg.GetMasterKey() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
if tokenString == servercfg.GetMasterKey() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func removeNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// get params
|
||||
var params = mux.Vars(r)
|
||||
// get params
|
||||
var params = mux.Vars(r)
|
||||
|
||||
success, err := serverctl.RemoveNetwork(params["network"])
|
||||
success, err := serverctl.RemoveNetwork(params["network"])
|
||||
|
||||
if err != nil || !success {
|
||||
json.NewEncoder(w).Encode("Could not remove server from network " + params["network"])
|
||||
return
|
||||
}
|
||||
if err != nil || !success {
|
||||
json.NewEncoder(w).Encode("Could not remove server from network " + params["network"])
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode("Server removed from network " + params["network"])
|
||||
json.NewEncoder(w).Encode("Server removed from network " + params["network"])
|
||||
}
|
||||
|
||||
func getConfig(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// get params
|
||||
// get params
|
||||
|
||||
scfg := servercfg.GetServerConfig()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(scfg)
|
||||
scfg := servercfg.GetServerConfig()
|
||||
json.NewEncoder(w).Encode(scfg)
|
||||
//w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
/*
|
||||
func getMongoConfig(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// get params
|
||||
|
||||
mcfg := servercfg.GetMongoConfig()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(mcfg)
|
||||
}
|
||||
*/
|
||||
|
||||
func addNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// get params
|
||||
var params = mux.Vars(r)
|
||||
// get params
|
||||
var params = mux.Vars(r)
|
||||
|
||||
success, err := serverctl.AddNetwork(params["network"])
|
||||
success, err := serverctl.AddNetwork(params["network"])
|
||||
|
||||
if err != nil || !success {
|
||||
json.NewEncoder(w).Encode("Could not add server to network " + params["network"])
|
||||
return
|
||||
}
|
||||
if err != nil || !success {
|
||||
json.NewEncoder(w).Encode("Could not add server to network " + params["network"])
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode("Server added to network " + params["network"])
|
||||
json.NewEncoder(w).Encode("Server added to network " + params["network"])
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ package database
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/rqlite/gorqlite"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
const NETWORKS_TABLE_NAME = "networks"
|
||||
|
@ -21,18 +20,32 @@ const DATABASE_FILENAME = "netmaker.db"
|
|||
const NO_RECORD = "no result found"
|
||||
const NO_RECORDS = "could not find any records"
|
||||
|
||||
var Database gorqlite.Connection
|
||||
// == Constants ==
|
||||
const INIT_DB = "init"
|
||||
const CREATE_TABLE = "createtable"
|
||||
const INSERT = "insert"
|
||||
const INSERT_PEER = "insertpeer"
|
||||
const DELETE = "delete"
|
||||
const DELETE_ALL = "deleteall"
|
||||
const FETCH_ALL = "fetchall"
|
||||
const CLOSE_DB = "closedb"
|
||||
|
||||
func getCurrentDB() map[string]interface{} {
|
||||
switch servercfg.GetDB() {
|
||||
case "rqlite":
|
||||
return RQLITE_FUNCTIONS
|
||||
case "sqlite":
|
||||
return SQLITE_FUNCTIONS
|
||||
default:
|
||||
return RQLITE_FUNCTIONS
|
||||
}
|
||||
}
|
||||
|
||||
func InitializeDatabase() error {
|
||||
|
||||
conn, err := gorqlite.Open("http://")
|
||||
if err != nil {
|
||||
if err := getCurrentDB()[INIT_DB].(func() error)(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sqliteDatabase, _ := sql.Open("sqlite3", "./database/"+dbFilename)
|
||||
Database = conn
|
||||
Database.SetConsistencyLevel("strong")
|
||||
createTables()
|
||||
return nil
|
||||
}
|
||||
|
@ -49,52 +62,36 @@ func createTables() {
|
|||
}
|
||||
|
||||
func createTable(tableName string) error {
|
||||
_, err := Database.WriteOne("CREATE TABLE IF NOT EXISTS " + tableName + " (key TEXT NOT NULL UNIQUE PRIMARY KEY, value TEXT)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return getCurrentDB()[CREATE_TABLE].(func(string) error)(tableName)
|
||||
}
|
||||
|
||||
func isJSONString(value string) bool {
|
||||
func IsJSONString(value string) bool {
|
||||
var jsonInt interface{}
|
||||
return json.Unmarshal([]byte(value), &jsonInt) == nil
|
||||
}
|
||||
|
||||
func Insert(key string, value string, tableName string) error {
|
||||
if key != "" && value != "" && isJSONString(value) {
|
||||
_, err := Database.WriteOne("INSERT OR REPLACE INTO " + tableName + " (key, value) VALUES ('" + key + "', '" + value + "')")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
return getCurrentDB()[INSERT].(func(string, string, string) error)(key, value, tableName)
|
||||
} else {
|
||||
return errors.New("invalid insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func InsertPeer(key string, value string) error {
|
||||
if key != "" && value != "" && isJSONString(value) {
|
||||
_, err := Database.WriteOne("INSERT OR REPLACE INTO " + PEERS_TABLE_NAME + " (key, value) VALUES ('" + key + "', '" + value + "')")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
return getCurrentDB()[INSERT_PEER].(func(string, string) error)(key, value)
|
||||
} else {
|
||||
return errors.New("invalid peer insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteRecord(tableName string, key string) error {
|
||||
_, err := Database.WriteOne("DELETE FROM " + tableName + " WHERE key = \"" + key + "\"")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return getCurrentDB()[DELETE].(func(string, string) error)(tableName, key)
|
||||
}
|
||||
|
||||
func DeleteAllRecords(tableName string) error {
|
||||
_, err := Database.WriteOne("DELETE TABLE " + tableName)
|
||||
err := getCurrentDB()[DELETE_ALL].(func(string) error)(tableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -117,19 +114,9 @@ func FetchRecord(tableName string, key string) (string, error) {
|
|||
}
|
||||
|
||||
func FetchRecords(tableName string) (map[string]string, error) {
|
||||
row, err := Database.QueryOne("SELECT * FROM " + tableName + " ORDER BY key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records := make(map[string]string)
|
||||
for row.Next() { // Iterate and fetch the records from result cursor
|
||||
var key string
|
||||
var value string
|
||||
row.Scan(&key, &value)
|
||||
records[key] = value
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return nil, errors.New(NO_RECORDS)
|
||||
}
|
||||
return records, nil
|
||||
return getCurrentDB()[FETCH_ALL].(func(string) (map[string]string, error))(tableName)
|
||||
}
|
||||
|
||||
func CloseDB() {
|
||||
getCurrentDB()[CLOSE_DB].(func())()
|
||||
}
|
||||
|
|
117
database/rqlite.go
Normal file
117
database/rqlite.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/rqlite/gorqlite"
|
||||
)
|
||||
|
||||
var RQliteDatabase gorqlite.Connection
|
||||
|
||||
var RQLITE_FUNCTIONS = map[string]interface{}{
|
||||
INIT_DB: initRqliteDatabase,
|
||||
CREATE_TABLE: rqliteCreateTable,
|
||||
INSERT: rqliteInsert,
|
||||
INSERT_PEER: rqliteInsertPeer,
|
||||
DELETE: rqliteDeleteRecord,
|
||||
DELETE_ALL: rqliteDeleteAllRecords,
|
||||
FETCH_ALL: rqliteFetchRecords,
|
||||
CLOSE_DB: rqliteCloseDB,
|
||||
}
|
||||
|
||||
func initRqliteDatabase() error {
|
||||
|
||||
conn, err := gorqlite.Open(servercfg.GetSQLConn())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
RQliteDatabase = conn
|
||||
RQliteDatabase.SetConsistencyLevel("strong")
|
||||
return nil
|
||||
}
|
||||
|
||||
func rqliteCreateTable(tableName string) error {
|
||||
_, err := RQliteDatabase.WriteOne("CREATE TABLE IF NOT EXISTS " + tableName + " (key TEXT NOT NULL UNIQUE PRIMARY KEY, value TEXT)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rqliteInsert(key string, value string, tableName string) error {
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
_, err := RQliteDatabase.WriteOne("INSERT OR REPLACE INTO " + tableName + " (key, value) VALUES ('" + key + "', '" + value + "')")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("invalid insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func rqliteInsertPeer(key string, value string) error {
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
_, err := RQliteDatabase.WriteOne("INSERT OR REPLACE INTO " + PEERS_TABLE_NAME + " (key, value) VALUES ('" + key + "', '" + value + "')")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("invalid peer insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func rqliteDeleteRecord(tableName string, key string) error {
|
||||
_, err := RQliteDatabase.WriteOne("DELETE FROM " + tableName + " WHERE key = \"" + key + "\"")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rqliteDeleteAllRecords(tableName string) error {
|
||||
_, err := RQliteDatabase.WriteOne("DELETE TABLE " + tableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rqliteCreateTable(tableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rqliteFetchRecord(tableName string, key string) (string, error) {
|
||||
results, err := FetchRecords(tableName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if results[key] == "" {
|
||||
return "", errors.New(NO_RECORD)
|
||||
}
|
||||
return results[key], nil
|
||||
}
|
||||
|
||||
func rqliteFetchRecords(tableName string) (map[string]string, error) {
|
||||
row, err := RQliteDatabase.QueryOne("SELECT * FROM " + tableName + " ORDER BY key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records := make(map[string]string)
|
||||
for row.Next() { // Iterate and fetch the records from result cursor
|
||||
var key string
|
||||
var value string
|
||||
row.Scan(&key, &value)
|
||||
records[key] = value
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return nil, errors.New(NO_RECORDS)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func rqliteCloseDB() {
|
||||
RQliteDatabase.Close()
|
||||
}
|
132
database/sqlite.go
Normal file
132
database/sqlite.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// == sqlite ==
|
||||
const dbFilename = "netmaker.db"
|
||||
|
||||
var SqliteDB *sql.DB
|
||||
|
||||
var SQLITE_FUNCTIONS = map[string]interface{}{
|
||||
INIT_DB: initSqliteDB,
|
||||
CREATE_TABLE: sqliteCreateTable,
|
||||
INSERT: sqliteInsert,
|
||||
INSERT_PEER: sqliteInsertPeer,
|
||||
DELETE: sqliteDeleteRecord,
|
||||
DELETE_ALL: sqliteDeleteAllRecords,
|
||||
FETCH_ALL: sqliteFetchRecords,
|
||||
CLOSE_DB: sqliteCloseDB,
|
||||
}
|
||||
|
||||
func initSqliteDB() error {
|
||||
// == create db file if not present ==
|
||||
if _, err := os.Stat("data"); os.IsNotExist(err) {
|
||||
os.Mkdir("data", 0644)
|
||||
}
|
||||
dbFilePath := filepath.Join("data", dbFilename)
|
||||
if _, err := os.Stat(dbFilePath); os.IsNotExist(err) {
|
||||
os.Create(dbFilePath)
|
||||
}
|
||||
// == "connect" the database ==
|
||||
var dbOpenErr error
|
||||
SqliteDB, dbOpenErr = sql.Open("sqlite3", dbFilePath)
|
||||
if dbOpenErr != nil {
|
||||
return dbOpenErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sqliteCreateTable(tableName string) error {
|
||||
statement, err := SqliteDB.Prepare("CREATE TABLE IF NOT EXISTS " + tableName + " (key TEXT NOT NULL UNIQUE PRIMARY KEY, value TEXT)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = statement.Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sqliteInsert(key string, value string, tableName string) error {
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
insertSQL := "INSERT OR REPLACE INTO " + tableName + " (key, value) VALUES (?, ?)"
|
||||
statement, err := SqliteDB.Prepare(insertSQL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = statement.Exec(key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("invalid insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func sqliteInsertPeer(key string, value string) error {
|
||||
if key != "" && value != "" && IsJSONString(value) {
|
||||
err := sqliteInsert(key, value, PEERS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("invalid peer insert " + key + " : " + value)
|
||||
}
|
||||
}
|
||||
|
||||
func sqliteDeleteRecord(tableName string, key string) error {
|
||||
deleteSQL := "DELETE FROM " + tableName + " WHERE key = \"" + key + "\""
|
||||
statement, err := SqliteDB.Prepare(deleteSQL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = statement.Exec(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sqliteDeleteAllRecords(tableName string) error {
|
||||
deleteSQL := "DELETE FROM " + tableName
|
||||
statement, err := SqliteDB.Prepare(deleteSQL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = statement.Exec(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sqliteFetchRecords(tableName string) (map[string]string, error) {
|
||||
row, err := SqliteDB.Query("SELECT * FROM " + tableName + " ORDER BY key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records := make(map[string]string)
|
||||
defer row.Close()
|
||||
for row.Next() { // Iterate and fetch the records from result cursor
|
||||
var key string
|
||||
var value string
|
||||
row.Scan(&key, &value)
|
||||
records[key] = value
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return nil, errors.New(NO_RECORDS)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func sqliteCloseDB() {
|
||||
SqliteDB.Close()
|
||||
}
|
|
@ -103,7 +103,7 @@ Make sure firewall settings are appropriate for Netmaker. You need ports 53 and
|
|||
|
||||
.. code-block::
|
||||
|
||||
sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow dns
|
||||
sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow 53/udp
|
||||
|
||||
**Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on:**
|
||||
- allow 443/tcp from all
|
||||
|
|
|
@ -175,7 +175,7 @@ This template is equivalent but omits CoreDNS.
|
|||
Linux Install without Docker
|
||||
=============================
|
||||
|
||||
Most systems support Docker, but some, such as LXC, 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).
|
||||
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).
|
||||
|
||||
To start, we recommend following the Nginx instructions in the :doc:`Quick Install <./quick-start>` guide to enable SSL for your environment.
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ UI
|
|||
**Can I have multiple nodes with the same name?**
|
||||
Yes, nodes can share names without issue. It may just be harder on you to know which is which.
|
||||
|
||||
Agent
|
||||
Netclient
|
||||
-------
|
||||
**How do I connect a node to my Netmaker network with Netclient?**
|
||||
First get your access token (not just access key), then run ``sudo netclient join -t <access token>``.
|
||||
|
@ -83,6 +83,13 @@ Agent
|
|||
**I am done with the agent on my machine, can I uninstall it?**
|
||||
Yes, on the node simply run ``sudo /etc/netclient/netclient uninstall``.
|
||||
|
||||
**I am running SELinux and when I reboot my node I get a permission denied in my netclient logs and it doesn't connect anymore, why?**
|
||||
If you're running SELinux, it will interfere with systemd's ability to restart the client properly. Therefore, please run the following:
|
||||
.. code-block::
|
||||
|
||||
sudo semanage fcontext -a -t bin_t '/etc/netclient/netclient'
|
||||
sudo chcon -Rv -u system_u -t bin_t '/etc/netclient/netclient'
|
||||
sudo restorecon -R -v /etc/netclient/netclient
|
||||
|
||||
CoreDNS
|
||||
--------
|
||||
|
|
|
@ -92,11 +92,25 @@ func CreateServerToken(netID string) (string, error) {
|
|||
}
|
||||
|
||||
var accessToken models.AccessToken
|
||||
servervals := models.ServerConfig{
|
||||
APIConnString: "127.0.0.1:" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
servervals := models.ServerConfig{}
|
||||
if servercfg.GetPlatform() == "Kubernetes" {
|
||||
log.Println("server on kubernetes")
|
||||
servervals = models.ServerConfig{
|
||||
APIConnString: servercfg.GetPodIP() + ":" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: servercfg.GetPodIP() + ":" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
}
|
||||
} 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",
|
||||
}
|
||||
}
|
||||
log.Println("APIConnString:",servervals.APIConnString)
|
||||
log.Println("GRPCConnString:",servervals.GRPCConnString)
|
||||
log.Println("GRPCSSL:",servervals.GRPCSSL)
|
||||
accessToken.ServerConfig = servervals
|
||||
accessToken.ClientConfig.Network = netID
|
||||
accessToken.ClientConfig.Key = GenKey()
|
||||
|
@ -104,14 +118,12 @@ func CreateServerToken(netID string) (string, error) {
|
|||
accesskey.Name = GenKeyName()
|
||||
accesskey.Value = accessToken.ClientConfig.Key
|
||||
accesskey.Uses = 1
|
||||
|
||||
tokenjson, err := json.Marshal(accessToken)
|
||||
if err != nil {
|
||||
return accesskey.AccessString, err
|
||||
}
|
||||
|
||||
accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
|
||||
|
||||
log.Println("accessstring:",accesskey.AccessString)
|
||||
network.AccessKeys = append(network.AccessKeys, accesskey)
|
||||
if data, err := json.Marshal(network); err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -20,11 +20,25 @@ func SetDNSDir() error {
|
|||
}
|
||||
_, err = os.Stat(dir + "/config/dnsconfig")
|
||||
if os.IsNotExist(err) {
|
||||
os.Mkdir(dir+"/config/dnsconfig", 744)
|
||||
os.Mkdir(dir+"/config/dnsconfig", 0744)
|
||||
} else if err != nil {
|
||||
PrintUserLog("","couldnt find or create /config/dnsconfig",0)
|
||||
return err
|
||||
}
|
||||
_, err = os.Stat(dir + "/config/dnsconfig/Corefile")
|
||||
if os.IsNotExist(err) {
|
||||
err = SetCorefile("example.com")
|
||||
if err != nil {
|
||||
PrintUserLog("",err.Error(),0)
|
||||
}
|
||||
}
|
||||
_, err = os.Stat(dir + "/config/dnsconfig/netmaker.hosts")
|
||||
if os.IsNotExist(err) {
|
||||
_, err = os.Create(dir + "/config/dnsconfig/netmaker.hosts")
|
||||
if err != nil {
|
||||
PrintUserLog("",err.Error(),0)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,13 @@ spec:
|
|||
hostNetwork: true
|
||||
containers:
|
||||
- name: netclient
|
||||
image: gravitl/netclient:v0.7
|
||||
image: gravitl/netclient:v0.7.2
|
||||
command: ['bash', '-c', "netclient checkin -n $NETWORK; sleep $SLEEP"]
|
||||
env:
|
||||
- name: ACCESS_TOKEN
|
||||
value: "XXXX"
|
||||
- name: NETWORK
|
||||
value: "default"
|
||||
value: "YYYY"
|
||||
- name: SLEEP
|
||||
value: 30
|
||||
volumeMounts:
|
||||
|
@ -35,7 +35,7 @@ spec:
|
|||
privileged: true
|
||||
initContainers:
|
||||
- name: netclient-join
|
||||
image: gravitl/netclient:v0.7
|
||||
image: gravitl/netclient:v0.7.2
|
||||
command: ['bash', '-c', "netclient join -t $ACCESS_TOKEN --daemon off"]
|
||||
env:
|
||||
- name: ACCESS_TOKEN
|
||||
|
|
361
kube/netmaker-template-udp.yaml
Normal file
361
kube/netmaker-template-udp.yaml
Normal file
|
@ -0,0 +1,361 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: rqlite-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: netmaker-backend
|
||||
labels:
|
||||
app: netmaker-backend
|
||||
spec:
|
||||
nodeSelector:
|
||||
netmaker-server: true
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netmaker-backend
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: netmaker-backend
|
||||
image: gravitl/netmaker:0.7.2
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
volumeMounts:
|
||||
- name: nm-pvc
|
||||
mountPath: /root/config/dnsconfig
|
||||
- mountPath: /etc/netclient
|
||||
name: etc-netclient
|
||||
- mountPath: /usr/bin/wg
|
||||
name: wg
|
||||
- mountPath: /var/run/dbus/system_bus_socket
|
||||
name: systemd-bus-socket
|
||||
- mountPath: /sys/fs/cgroup
|
||||
name: cgroup
|
||||
- mountPath: /run/systemd/system
|
||||
name: run-systemd
|
||||
- mountPath: /etc/systemd/system
|
||||
name: etc-systemd
|
||||
securityContext:
|
||||
privileged: true
|
||||
env:
|
||||
- name: SERVER_API_CONN_STRING
|
||||
value: "api.NETMAKER_BASE_DOMAIN:443"
|
||||
- name: SERVER_GRPC_CONN_STRING
|
||||
value: "grpc.NETMAKER_BASE_DOMAIN:443"
|
||||
- name: COREDNS_ADDR
|
||||
value: "10.152.183.53"
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
- name: GRPC_SSL
|
||||
value: "on"
|
||||
- name: SERVER_HTTP_HOST
|
||||
value: "api.NETMAKER_BASE_DOMAIN:443"
|
||||
- name: SERVER_GRPC_HOST
|
||||
value: "grpc.NETMAKER_BASE_DOMAIN:443"
|
||||
- name: API_PORT
|
||||
value: "8081"
|
||||
- name: GRPC_PORT
|
||||
value: "443"
|
||||
- name: CLIENT_MODE
|
||||
value: "off"
|
||||
- name: MASTER_KEY
|
||||
value: "Unkn0wn!"
|
||||
- name: PLATFORM
|
||||
value: "Kubernetes"
|
||||
- name: CORS_ALLOWED_ORIGIN
|
||||
value: "*"
|
||||
- name: rqlite
|
||||
image: rqlite/rqlite
|
||||
ports:
|
||||
- containerPort: 4001
|
||||
- containerPort: 4002
|
||||
volumeMounts:
|
||||
- name: rqlitevol
|
||||
mountPath: /rqlite/file/data
|
||||
volumes:
|
||||
- name: rqlitevol
|
||||
persistentVolumeClaim:
|
||||
claimName: rqlite-pvc
|
||||
- name: nm-pvc
|
||||
persistentVolumeClaim:
|
||||
claimName: nm-pvc
|
||||
- hostPath:
|
||||
path: /etc/netclient
|
||||
type: DirectoryOrCreate
|
||||
name: etc-netclient
|
||||
- hostPath:
|
||||
path: /usr/bin/wg
|
||||
type: File
|
||||
name: wg
|
||||
- hostPath:
|
||||
path: /usr/bin/resolvectl
|
||||
type: File
|
||||
name: resolvectl
|
||||
- hostPath:
|
||||
path: /var/run/dbus/system_bus_socket
|
||||
type: ""
|
||||
name: systemd-bus-socket
|
||||
- hostPath:
|
||||
path: /etc/systemd/system
|
||||
type: ""
|
||||
name: etc-systemd
|
||||
- hostPath:
|
||||
path: /run/systemd/system
|
||||
type: ""
|
||||
name: run-systemd
|
||||
- hostPath:
|
||||
path: /sys/fs/cgroup
|
||||
type: ""
|
||||
name: cgroup
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: nm-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-backend
|
||||
name: netmaker-api
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
protocol: TCP
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: netmaker-backend
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-backend
|
||||
name: netmaker-grpc
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
targetPort: 443
|
||||
selector:
|
||||
app: netmaker-backend
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: netmaker-dns
|
||||
labels:
|
||||
app: netmaker-dns
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netmaker-dns
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-dns
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- -conf
|
||||
- /root/dnsconfig/Corefile
|
||||
image: coredns/coredns
|
||||
imagePullPolicy: Always
|
||||
name: netmaker-dns
|
||||
ports:
|
||||
- containerPort: 53
|
||||
name: dns
|
||||
protocol: UDP
|
||||
- containerPort: 53
|
||||
name: dns-tcp
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- mountPath: /root/dnsconfig
|
||||
name: nm-pvc
|
||||
readOnly: true
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
add:
|
||||
- NET_BIND_SERVICE
|
||||
drop:
|
||||
- all
|
||||
dnsPolicy: "None"
|
||||
dnsConfig:
|
||||
nameservers:
|
||||
- 127.0.0.1
|
||||
volumes:
|
||||
- name: nm-pvc
|
||||
persistentVolumeClaim:
|
||||
claimName: nm-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-dns
|
||||
name: netmaker-dns
|
||||
spec:
|
||||
ports:
|
||||
- port: 53
|
||||
protocol: UDP
|
||||
targetPort: 53
|
||||
name: udp
|
||||
- port: 53
|
||||
protocol: TCP
|
||||
targetPort: 53
|
||||
name: tcp
|
||||
selector:
|
||||
app: netmaker-dns
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
clusterIP: 10.152.183.53
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: netmaker-ui
|
||||
labels:
|
||||
app: netmaker-ui
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netmaker-ui
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-ui
|
||||
spec:
|
||||
containers:
|
||||
- name: netmaker-ui
|
||||
image: gravitl/netmaker-ui:v0.7
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: BACKEND_URL
|
||||
value: "https://api.NETMAKER_BASE_DOMAIN"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: netmaker-ui
|
||||
name: netmaker-ui
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: netmaker-ui
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nm-api-ingress-nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- api.NETMAKER_BASE_DOMAIN
|
||||
secretName: nm-api-tls
|
||||
rules:
|
||||
- host: api.NETMAKER_BASE_DOMAIN
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: netmaker-api
|
||||
port:
|
||||
number: 8081
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nm-grpc-ingress-nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- grpc.NETMAKER_BASE_DOMAIN
|
||||
secretName: nm-grpc-tls
|
||||
rules:
|
||||
- host: grpc.NETMAKER_BASE_DOMAIN
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: netmaker-grpc
|
||||
port:
|
||||
number: 443
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nm-ui-ingress-nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- dashboard.NETMAKER_BASE_DOMAIN
|
||||
secretName: nm-ui-tls
|
||||
rules:
|
||||
- host: dashboard.NETMAKER_BASE_DOMAIN
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: netmaker-ui
|
||||
port:
|
||||
number: 80
|
|
@ -1,62 +1,14 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mongo
|
||||
labels:
|
||||
name: mongo
|
||||
spec:
|
||||
ports:
|
||||
- port: 27017
|
||||
targetPort: 27017
|
||||
clusterIP: None
|
||||
selector:
|
||||
role: mongo
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: mongo
|
||||
spec:
|
||||
serviceName: "mongo"
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
role: mongo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mongo
|
||||
role: mongo
|
||||
spec:
|
||||
containers:
|
||||
- name: mongo
|
||||
image: mongo
|
||||
env:
|
||||
- name: MONGO_INITDB_ROOT_USERNAME
|
||||
value: mongoadmin
|
||||
- name: MONGO_INITDB_ROOT_PASSWORD
|
||||
value: mongopass
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: mongovol
|
||||
mountPath: /data/db
|
||||
volumes:
|
||||
- name: mongovol
|
||||
persistentVolumeClaim:
|
||||
claimName: mongodb-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mongodb-pvc
|
||||
name: rqlite-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 7Gi
|
||||
storageClassName: microk8s-hostpath
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
|
@ -69,6 +21,8 @@ spec:
|
|||
matchLabels:
|
||||
app: netmaker-backend
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
|
@ -77,11 +31,11 @@ spec:
|
|||
containers:
|
||||
- name: netmaker-backend
|
||||
image: gravitl/netmaker:v0.7
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
volumeMounts:
|
||||
- name: nm-pvc
|
||||
mountPath: /root/config/dnsconfig
|
||||
securityContext:
|
||||
privileged: true
|
||||
env:
|
||||
- name: SERVER_API_CONN_STRING
|
||||
value: "api.NETMAKER_BASE_DOMAIN:443"
|
||||
|
@ -89,6 +43,10 @@ spec:
|
|||
value: "grpc.NETMAKER_BASE_DOMAIN:443"
|
||||
- name: COREDNS_ADDR
|
||||
value: "10.152.183.53"
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
- name: GRPC_SSL
|
||||
value: "on"
|
||||
- name: SERVER_HTTP_HOST
|
||||
|
@ -98,26 +56,27 @@ spec:
|
|||
- name: API_PORT
|
||||
value: "8081"
|
||||
- name: GRPC_PORT
|
||||
value: "443"
|
||||
value: "80"
|
||||
- name: CLIENT_MODE
|
||||
value: "off"
|
||||
- name: MASTER_KEY
|
||||
value: "Unkn0wn!"
|
||||
- name: SERVER_GRPC_WIREGUARD
|
||||
value: "off"
|
||||
- name: MASTER_KEY
|
||||
value: "secretkey"
|
||||
- name: PLATFORM
|
||||
value: "Kubernetes"
|
||||
- name: CORS_ALLOWED_ORIGIN
|
||||
value: "*"
|
||||
- name: MONGO_ADMIN
|
||||
value: "mongoadmin"
|
||||
- name: MONGO_PASS
|
||||
value: "mongopass"
|
||||
- name: MONGO_HOST
|
||||
value: "mongo-0.mongo"
|
||||
- name: MONGO_OPTS
|
||||
value: "/?authSource=admin"
|
||||
- name: rqlite
|
||||
image: rqlite/rqlite
|
||||
ports:
|
||||
- containerPort: 4001
|
||||
- containerPort: 4002
|
||||
volumeMounts:
|
||||
- name: rqlitevol
|
||||
mountPath: /rqlite/file/data
|
||||
volumes:
|
||||
- name: rqlitevol
|
||||
persistentVolumeClaim:
|
||||
claimName: rqlite-pvc
|
||||
- name: nm-pvc
|
||||
persistentVolumeClaim:
|
||||
claimName: nm-pvc
|
||||
|
@ -132,7 +91,6 @@ spec:
|
|||
resources:
|
||||
requests:
|
||||
storage: 128Mi
|
||||
storageClassName: microk8s-hostpath
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
@ -288,7 +246,7 @@ metadata:
|
|||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
spec:
|
||||
ingressClassName: public
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- api.NETMAKER_BASE_DOMAIN
|
||||
|
@ -314,7 +272,7 @@ metadata:
|
|||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
|
||||
spec:
|
||||
ingressClassName: public
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- grpc.NETMAKER_BASE_DOMAIN
|
||||
|
@ -340,7 +298,7 @@ metadata:
|
|||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||||
spec:
|
||||
ingressClassName: public
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- dashboard.NETMAKER_BASE_DOMAIN
|
||||
|
|
30
kube/ubuntu.yaml
Normal file
30
kube/ubuntu.yaml
Normal file
|
@ -0,0 +1,30 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: ubuntu
|
||||
labels:
|
||||
app: ubuntu
|
||||
spec:
|
||||
# Uncomment and specify a specific node you want to debug
|
||||
# nodeName: <insert-node-name-here>
|
||||
containers:
|
||||
- image: ubuntu
|
||||
command:
|
||||
- "sleep"
|
||||
- "3600"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: ubuntu
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: rootfolder
|
||||
mountPath: /
|
||||
restartPolicy: Never
|
||||
hostIPC: true
|
||||
hostNetwork: true
|
||||
hostPID: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /
|
||||
type: ""
|
||||
name: rootfolder
|
4
main.go
4
main.go
|
@ -26,7 +26,7 @@ import (
|
|||
func main() {
|
||||
fmt.Println(models.RetrieveLogo()) // print the logo
|
||||
initialize() // initial db and grpc server
|
||||
defer database.Database.Close()
|
||||
defer database.CloseDB()
|
||||
startControllers() // start the grpc or rest endpoints
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func initialize() { // Client Mode Prereq Check
|
|||
|
||||
if err != nil {
|
||||
log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
|
||||
log.Fatal(err)
|
||||
log.Fatal(output, err)
|
||||
}
|
||||
uid, err := strconv.Atoi(string(output[:len(output)-1]))
|
||||
if err != nil {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
)
|
||||
|
@ -215,7 +215,11 @@ func (network *Network) SetNetworkLastModified() {
|
|||
|
||||
func (network *Network) SetDefaults() {
|
||||
if network.DefaultUDPHolePunch == "" {
|
||||
network.DefaultUDPHolePunch = "yes"
|
||||
if servercfg.IsClientMode() {
|
||||
network.DefaultUDPHolePunch = "yes"
|
||||
} else {
|
||||
network.DefaultUDPHolePunch = "no"
|
||||
}
|
||||
}
|
||||
if network.IsLocal == "" {
|
||||
network.IsLocal = "no"
|
||||
|
|
Binary file not shown.
|
@ -10,7 +10,6 @@ import (
|
|||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
|
@ -314,17 +313,13 @@ func RemoveLocalInstance(cfg *config.ClientConfig, networkName string) error {
|
|||
|
||||
func DeleteInterface(ifacename string, postdown string) error {
|
||||
ipExec, err := exec.LookPath("ip")
|
||||
|
||||
cmdIPLinkDel := &exec.Cmd{
|
||||
Path: ipExec,
|
||||
Args: []string{ipExec, "link", "del", ifacename},
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
}
|
||||
err = cmdIPLinkDel.Run()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
out, err := local.RunCmd(ipExec + " link del " + ifacename)
|
||||
if err != nil {
|
||||
log.Println(out, err)
|
||||
}
|
||||
if postdown != "" {
|
||||
runcmds := strings.Split(postdown, "; ")
|
||||
err = local.RunCmds(runcmds)
|
||||
|
|
|
@ -136,12 +136,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
cfg.Node.MacAddress = macs[0]
|
||||
}
|
||||
}
|
||||
if cfg.Node.ListenPort == 0 {
|
||||
cfg.Node.ListenPort, err = GetFreePort(51821)
|
||||
if err != nil {
|
||||
fmt.Printf("Error retrieving port: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
var requestOpts grpc.DialOption
|
||||
requestOpts = grpc.WithInsecure()
|
||||
|
@ -174,6 +169,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
SaveConfig: cfg.Node.SaveConfig,
|
||||
UDPHolePunch: cfg.Node.UDPHolePunch,
|
||||
}
|
||||
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -200,6 +196,13 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if node.ListenPort == 0 {
|
||||
node.ListenPort, err = GetFreePort(51821)
|
||||
if err != nil {
|
||||
fmt.Printf("Error retrieving port: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if node.DNSOn == "yes" {
|
||||
cfg.Node.DNSOn = "yes"
|
||||
}
|
||||
|
|
|
@ -274,22 +274,21 @@ func WipeLocal(network string) error {
|
|||
if FileExists(home + "/nettoken-" + network) {
|
||||
_ = os.Remove(home + "/nettoken-" + network)
|
||||
}
|
||||
if FileExists(home + "/secret-" + network) {
|
||||
_ = os.Remove(home + "/secret-" + network)
|
||||
}
|
||||
if FileExists(home + "/wgkey-" + network) {
|
||||
_ = os.Remove(home + "/wgkey-" + network)
|
||||
}
|
||||
|
||||
ipExec, err := exec.LookPath("ip")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ifacename != "" {
|
||||
cmdIPLinkDel := &exec.Cmd{
|
||||
Path: ipExec,
|
||||
Args: []string{ipExec, "link", "del", ifacename},
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
}
|
||||
err = cmdIPLinkDel.Run()
|
||||
out, err := RunCmd(ipExec + " link del " + ifacename)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println(out, err)
|
||||
}
|
||||
if nodecfg.PostDown != "" {
|
||||
runcmds := strings.Split(nodecfg.PostDown, "; ")
|
||||
|
|
|
@ -316,7 +316,7 @@ func main() {
|
|||
out, err := local.RunCmd("id -u")
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal(out, err)
|
||||
}
|
||||
id, err := strconv.Atoi(string(out[:len(out)-1]))
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -65,16 +65,17 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
}
|
||||
|
||||
_, delErr := local.RunCmd("ip link delete dev " + ifacename)
|
||||
_, addLinkErr := local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard")
|
||||
_, addErr := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24")
|
||||
addLinkOut, addLinkErr := local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard")
|
||||
addOut, addErr := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24")
|
||||
if delErr != nil {
|
||||
// pass
|
||||
// not displaying error
|
||||
// log.Println(delOut, delErr)
|
||||
}
|
||||
if addLinkErr != nil {
|
||||
log.Println(addLinkErr)
|
||||
log.Println(addLinkOut, addLinkErr)
|
||||
}
|
||||
if addErr != nil {
|
||||
log.Println(addErr)
|
||||
log.Println(addOut, addErr)
|
||||
}
|
||||
var nodeport int
|
||||
nodeport = int(node.ListenPort)
|
||||
|
@ -122,21 +123,11 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
_ = local.UpdateDNS(ifacename, network, nameserver)
|
||||
}
|
||||
//=========End DNS Setup=======\\
|
||||
|
||||
cmdIPLinkUp := &exec.Cmd{
|
||||
Path: ipExec,
|
||||
Args: []string{ipExec, "link", "set", "up", "dev", ifacename},
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
if ipLinkDownOut, err := local.RunCmd(ipExec + " link set down dev " + ifacename); err != nil {
|
||||
log.Println(ipLinkDownOut, err)
|
||||
return err
|
||||
}
|
||||
|
||||
cmdIPLinkDown := &exec.Cmd{
|
||||
Path: ipExec,
|
||||
Args: []string{ipExec, "link", "set", "down", "dev", ifacename},
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
}
|
||||
err = cmdIPLinkDown.Run()
|
||||
if nodecfg.PostDown != "" {
|
||||
runcmds := strings.Split(nodecfg.PostDown, "; ")
|
||||
err = local.RunCmds(runcmds)
|
||||
|
@ -145,8 +136,8 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
}
|
||||
}
|
||||
|
||||
err = cmdIPLinkUp.Run()
|
||||
if err != nil {
|
||||
if ipLinkUpOut, err := local.RunCmd(ipExec + " link set up dev " + ifacename); err != nil {
|
||||
log.Println(ipLinkUpOut, err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -162,16 +153,16 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
out, err := local.RunCmd(ipExec + " -4 route add " + gateway + " dev " + ifacename)
|
||||
fmt.Println(string(out))
|
||||
if err != nil {
|
||||
fmt.Println("Error encountered adding gateway: " + err.Error())
|
||||
fmt.Println("error encountered adding gateway: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Address6 != "" && node.IsDualStack == "yes" {
|
||||
fmt.Println("Adding address: " + node.Address6)
|
||||
fmt.Println("adding address: " + node.Address6)
|
||||
out, err := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address6 + "/64")
|
||||
if err != nil {
|
||||
fmt.Println(out)
|
||||
fmt.Println("Error encountered adding ipv6: " + err.Error())
|
||||
fmt.Println("error encountered adding ipv6: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,9 +259,9 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
|
|||
for _, currentPeer := range devicePeers {
|
||||
if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
|
||||
currentPeer.PublicKey.String() != peer.PublicKey.String() {
|
||||
_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
|
||||
output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
|
||||
if err != nil {
|
||||
log.Println("error removing peer", peer.Endpoint.String())
|
||||
log.Println(output, "error removing peer", peer.Endpoint.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,18 +276,19 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
|
|||
if keepAliveString == "0" {
|
||||
keepAliveString = "5"
|
||||
}
|
||||
var output string
|
||||
if peer.Endpoint != nil {
|
||||
_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
|
||||
output, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
|
||||
" endpoint " + udpendpoint +
|
||||
" persistent-keepalive " + keepAliveString +
|
||||
" allowed-ips " + allowedips)
|
||||
} else {
|
||||
_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
|
||||
output, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
|
||||
" persistent-keepalive " + keepAliveString +
|
||||
" allowed-ips " + allowedips)
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("error setting peer", peer.PublicKey.String(), err)
|
||||
log.Println(output, "error setting peer", peer.PublicKey.String(), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,15 +300,15 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
|
|||
}
|
||||
}
|
||||
if shouldDelete {
|
||||
_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
|
||||
output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
|
||||
if err != nil {
|
||||
log.Println("error removing peer", currentPeer.PublicKey.String())
|
||||
log.Println(output, "error removing peer", currentPeer.PublicKey.String())
|
||||
} else {
|
||||
log.Println("removed peer " + currentPeer.PublicKey.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ fi
|
|||
|
||||
[ -z "$KEY" ] && KEY=nokey;
|
||||
|
||||
wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.7/netclient
|
||||
wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.7.2/netclient
|
||||
chmod +x netclient
|
||||
sudo ./netclient join -t $KEY
|
||||
rm -f netclient
|
||||
|
|
|
@ -58,6 +58,9 @@ func GetServerConfig() config.ServerConfig {
|
|||
if DisableDefaultNet() {
|
||||
cfg.DisableRemoteIPCheck = "on"
|
||||
}
|
||||
cfg.Database = GetDB()
|
||||
cfg.Platform = GetPlatform()
|
||||
cfg.Version = GetVersion()
|
||||
return cfg
|
||||
}
|
||||
func GetAPIConnString() string {
|
||||
|
@ -69,6 +72,22 @@ func GetAPIConnString() string {
|
|||
}
|
||||
return conn
|
||||
}
|
||||
func GetVersion() string {
|
||||
version := "0.7.2"
|
||||
if config.Config.Server.Version != "" {
|
||||
version = config.Config.Server.Version
|
||||
}
|
||||
return version
|
||||
}
|
||||
func GetDB() string {
|
||||
database := "rqlite"
|
||||
if os.Getenv("DATABASE") == "sqlite" {
|
||||
database = os.Getenv("DATABASE")
|
||||
} else if config.Config.Server.Database == "sqlite" {
|
||||
database = config.Config.Server.Database
|
||||
}
|
||||
return database
|
||||
}
|
||||
func GetAPIHost() string {
|
||||
serverhost := "127.0.0.1"
|
||||
remoteip, _ := GetPublicIP()
|
||||
|
@ -85,6 +104,14 @@ func GetAPIHost() string {
|
|||
}
|
||||
return serverhost
|
||||
}
|
||||
func GetPodIP() string {
|
||||
podip := "127.0.0.1"
|
||||
if os.Getenv("POD_IP") != "" {
|
||||
podip = os.Getenv("POD_IP")
|
||||
}
|
||||
return podip
|
||||
}
|
||||
|
||||
func GetAPIPort() string {
|
||||
apiport := "8081"
|
||||
if os.Getenv("API_PORT") != "" {
|
||||
|
@ -117,13 +144,13 @@ func GetGRPCConnString() string {
|
|||
}
|
||||
|
||||
func GetCoreDNSAddr() string {
|
||||
addr, _ := GetPublicIP()
|
||||
if os.Getenv("COREDNS_ADDR") != "" {
|
||||
addr = os.Getenv("COREDNS_ADDR")
|
||||
} else if config.Config.Server.CoreDNSAddr != "" {
|
||||
addr = config.Config.Server.GRPCConnString
|
||||
}
|
||||
return addr
|
||||
addr, _ := GetPublicIP()
|
||||
if os.Getenv("COREDNS_ADDR") != "" {
|
||||
addr = os.Getenv("COREDNS_ADDR")
|
||||
} else if config.Config.Server.CoreDNSAddr != "" {
|
||||
addr = config.Config.Server.GRPCConnString
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func GetGRPCHost() string {
|
||||
|
@ -299,3 +326,23 @@ func GetVerbose() int32 {
|
|||
}
|
||||
return int32(level)
|
||||
}
|
||||
|
||||
func GetPlatform() string {
|
||||
platform := "linux"
|
||||
if os.Getenv("PLATFORM") != "" {
|
||||
platform = os.Getenv("PLATFORM")
|
||||
} else if config.Config.Server.Platform != "" {
|
||||
platform = config.Config.Server.SQLConn
|
||||
}
|
||||
return platform
|
||||
}
|
||||
|
||||
func GetSQLConn() string {
|
||||
sqlconn := "http://"
|
||||
if os.Getenv("SQL_CONN") != "" {
|
||||
sqlconn = os.Getenv("SQL_CONN")
|
||||
} else if config.Config.Server.SQLConn != "" {
|
||||
sqlconn = config.Config.Server.SQLConn
|
||||
}
|
||||
return sqlconn
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue