config.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. package daemon
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "log"
  7. "net"
  8. "net/netip"
  9. "os"
  10. "strings"
  11. "time"
  12. "github.com/joho/godotenv"
  13. )
  14. const LogMsgTmpl = "YOSAI Daemon ||| time: %s ||| %s\n"
  15. var EnvironmentVariables = []string{
  16. "HASHICORP_VAULT_URL",
  17. "HASHICORP_VAULT_KEY",
  18. "SEMAPHORE_SERVER_URL",
  19. }
  20. const DefaultConfigLoc = "./.config.json"
  21. type Configuration interface {
  22. SetServerName(val string)
  23. SetRepo(val string)
  24. SetBranch(val string)
  25. SetPlaybookName(val string)
  26. SetImage(val string)
  27. SetRegion(val string)
  28. SetLinodeType(val string)
  29. SetVpnServer(val string)
  30. SetVpnServerId(val int)
  31. SetVpnNetwork(val string) error
  32. SetSecretsBackend(val string)
  33. SetSecretsBackendUrl(val string)
  34. VpnClientIpAddr() string
  35. VpnServerIpAddr() string
  36. VpnServerPort() int
  37. VpnServerNetwork() string
  38. VpnServerId() int
  39. VpnServer() string
  40. ServerName() string
  41. GetServer(priority int8) (VpnServer, error)
  42. SecretsBackend() string
  43. SecretsBackendUrl() string
  44. Repo() string
  45. Branch() string
  46. PlaybookName() string
  47. Image() string
  48. Region() string
  49. LinodeType() string
  50. Log(data ...string)
  51. ConfigRouter(msg SockMessage) SockMessage
  52. Save(path string) error
  53. }
  54. /*
  55. Loads in the environment variable file at path, and then validates that all values in vars is present
  56. :param path: the path to the .env file
  57. :param vars: the list of variables to check were loaded by godotenv.Load()
  58. */
  59. func LoadAndVerifyEnv(path string, vars []string) error {
  60. err := godotenv.Load(".env")
  61. if err != nil {
  62. return err
  63. }
  64. var missing []string
  65. for i := range vars {
  66. val := os.Getenv(vars[i])
  67. if val == "" {
  68. missing = append(missing, vars[i])
  69. }
  70. }
  71. if len(missing) != 0 {
  72. return &EnvironmentVariableNotSet{Vars: missing}
  73. }
  74. return nil
  75. }
  76. type EnvironmentVariableNotSet struct {
  77. Vars []string
  78. }
  79. func (e *EnvironmentVariableNotSet) Error() string {
  80. return fmt.Sprintf("Environment variables: %v not set!", e.Vars)
  81. }
  82. func BlankEnv(path string) error {
  83. var data string
  84. for i := range EnvironmentVariables {
  85. data = data + fmt.Sprintf("%s=\n", EnvironmentVariables[i])
  86. }
  87. return os.WriteFile(path, []byte(data), 0666)
  88. }
  89. // Implemeting the interface to make this callable via the CLI
  90. func (c *ConfigFromFile) ConfigRouter(msg SockMessage) SockMessage {
  91. switch msg.Method {
  92. case "show":
  93. b, err := json.MarshalIndent(&c, "", " ")
  94. if err != nil {
  95. return *NewSockMessage(MsgResponse, REQUEST_FAILED, []byte(err.Error()))
  96. }
  97. return *NewSockMessage(MsgResponse, REQUEST_OK, b)
  98. case "save":
  99. err := c.Save(DefaultConfigLoc)
  100. if err != nil {
  101. return *NewSockMessage(MsgResponse, REQUEST_FAILED, []byte(err.Error()))
  102. }
  103. return *NewSockMessage(MsgResponse, REQUEST_OK, []byte("Configuration saved successfully."))
  104. case "reload":
  105. b, err := os.ReadFile(DefaultConfigLoc)
  106. if err != nil {
  107. return *NewSockMessage(MsgResponse, REQUEST_FAILED, []byte(err.Error()))
  108. }
  109. err = json.Unmarshal(b, c)
  110. if err != nil {
  111. return *NewSockMessage(MsgResponse, REQUEST_FAILED, []byte(err.Error()))
  112. }
  113. return *NewSockMessage(MsgResponse, REQUEST_OK, []byte("Configuration reloaded successfully."))
  114. default:
  115. return *NewSockMessage(MsgResponse, REQUEST_UNRESOLVED, []byte("Unresolved Method"))
  116. }
  117. }
  118. type ConfigFromFile struct {
  119. stream io.Writer
  120. Cloud cloudConfig `json:"cloud"`
  121. Ansible ansibleConfig `json:"ansible"`
  122. Service serviceConfig `json:"service"`
  123. }
  124. type ansibleConfig struct {
  125. Repo string `json:"repo_url"`
  126. Branch string `json:"branch"`
  127. PlaybookName string `json:"playbook_name"`
  128. }
  129. type serviceConfig struct {
  130. Servers []VpnServer
  131. VpnServer string `json:"vpn_server"`
  132. VpnServerId int `json:"vpn_server_id"`
  133. VpnServerName string `json:"vpn_server_name"`
  134. VpnServerNetwork string `json:"vpn_server_network"`
  135. VpnServerIPv4 string `json:"vpn_server_ipv4"`
  136. VpnServerPort int `json:"vpn_server_port"`
  137. VpnClientIPv4 string `json:"vpn_client_ipv4"`
  138. SecretsBackend string `json:"secrets_backend"`
  139. SecretsBackendUrl string `json:"secrets_backend_url"`
  140. }
  141. func (c *ConfigFromFile) GetServer(priority int8) (VpnServer, error) {
  142. for i := range c.Service.Servers {
  143. if c.Service.Servers[i].Priority == priority {
  144. return c.Service.Servers[i], nil
  145. }
  146. }
  147. return VpnServer{}, &ServerNotFound{}
  148. }
  149. type VpnServer struct {
  150. WanIpv4 string
  151. Fqdn string
  152. WgPort int
  153. ServerLabel string
  154. VpnIpv4 net.IPAddr
  155. Priority int8
  156. }
  157. type ServerNotFound struct{}
  158. func (s *ServerNotFound) Error() string { return "Server with the priority passed was not found." }
  159. func (c *ConfigFromFile) SetRepo(val string) { c.Ansible.Repo = val }
  160. func (c *ConfigFromFile) SetBranch(val string) { c.Ansible.Branch = val }
  161. func (c *ConfigFromFile) SetPlaybookName(val string) { c.Ansible.PlaybookName = val }
  162. func (c *ConfigFromFile) SetImage(val string) { c.Cloud.Image = val }
  163. func (c *ConfigFromFile) SetRegion(val string) { c.Cloud.Region = val }
  164. func (c *ConfigFromFile) SetLinodeType(val string) { c.Cloud.LinodeType = val }
  165. func (c *ConfigFromFile) SetVpnServer(val string) { c.Service.VpnServer = val }
  166. func (c *ConfigFromFile) SetVpnServerId(val int) { c.Service.VpnServerId = val }
  167. func (c *ConfigFromFile) SetServerName(val string) { c.Service.VpnServerName = val }
  168. func (c *ConfigFromFile) SetSecretsBackend(val string) { c.Service.SecretsBackend = val }
  169. func (c *ConfigFromFile) SetSecretsBackendUrl(val string) { c.Service.SecretsBackendUrl = val }
  170. func (c *ConfigFromFile) SetVpnNetwork(val string) error {
  171. addr, ntwrk, err := net.ParseCIDR(val)
  172. if err != nil {
  173. return err
  174. }
  175. ntwrkSp := strings.Split(ntwrk.String(), "/")
  176. cidr := ntwrkSp[1]
  177. parsed, _ := netip.ParseAddr(addr.String())
  178. clientIp := parsed.Next()
  179. serverIp := clientIp.Next()
  180. c.Service.VpnServerNetwork = ntwrk.String()
  181. c.Service.VpnServerIPv4 = serverIp.String() + "/" + cidr
  182. c.Service.VpnClientIPv4 = clientIp.String() + "/" + cidr
  183. return nil
  184. }
  185. func (c *ConfigFromFile) Repo() string {
  186. return c.Ansible.Repo
  187. }
  188. func (c *ConfigFromFile) Branch() string {
  189. return c.Ansible.Branch
  190. }
  191. func (c *ConfigFromFile) PlaybookName() string { return c.Ansible.PlaybookName }
  192. type cloudConfig struct {
  193. Image string `json:"image"`
  194. Region string `json:"region"`
  195. LinodeType string `json:"linode_type"`
  196. }
  197. func (c *ConfigFromFile) Image() string {
  198. return c.Cloud.Image
  199. }
  200. func (c *ConfigFromFile) Region() string {
  201. return c.Cloud.Region
  202. }
  203. func (c *ConfigFromFile) LinodeType() string {
  204. return c.Cloud.LinodeType
  205. }
  206. func (c *ConfigFromFile) VpnServerId() int {
  207. return c.Service.VpnServerId
  208. }
  209. func (c *ConfigFromFile) VpnServer() string {
  210. return c.Service.VpnServer
  211. }
  212. func (c *ConfigFromFile) ServerName() string {
  213. return c.Service.VpnServerName
  214. }
  215. func (c *ConfigFromFile) VpnServerIpAddr() string {
  216. return c.Service.VpnServerIPv4
  217. }
  218. func (c *ConfigFromFile) VpnClientIpAddr() string {
  219. return c.Service.VpnClientIPv4
  220. }
  221. func (c *ConfigFromFile) VpnServerNetwork() string {
  222. return c.Service.VpnServerNetwork
  223. }
  224. func (c *ConfigFromFile) VpnServerPort() int {
  225. return c.Service.VpnServerPort
  226. }
  227. func (c *ConfigFromFile) SecretsBackend() string {
  228. return c.Service.SecretsBackend
  229. }
  230. func (c *ConfigFromFile) SecretsBackendUrl() string {
  231. return c.Service.SecretsBackendUrl
  232. }
  233. /*
  234. Log a message to the Contexts 'stream' io.Writer interface
  235. */
  236. func (c *ConfigFromFile) Log(data ...string) {
  237. c.stream.Write([]byte(fmt.Sprintf(LogMsgTmpl, time.Now().String(), data)))
  238. }
  239. func ReadConfig(path string) Configuration {
  240. b, err := os.ReadFile(path)
  241. if err != nil {
  242. log.Fatal(err)
  243. }
  244. var config ConfigFromFile
  245. config = ConfigFromFile{
  246. stream: os.Stdout,
  247. }
  248. err = json.Unmarshal(b, &config)
  249. if err != nil {
  250. log.Fatal(err)
  251. }
  252. return &config
  253. }
  254. func (c *ConfigFromFile) Save(path string) error {
  255. b, err := json.MarshalIndent(c, " ", " ")
  256. if err != nil {
  257. return err
  258. }
  259. return os.WriteFile(path, b, 0666)
  260. }
  261. func BlankConfig(path string) error {
  262. config := ConfigFromFile{
  263. Cloud: cloudConfig{
  264. Image: "",
  265. Region: "",
  266. LinodeType: "",
  267. },
  268. Ansible: ansibleConfig{
  269. Repo: "",
  270. Branch: "",
  271. },
  272. }
  273. b, err := json.Marshal(config)
  274. if err != nil {
  275. return err
  276. }
  277. os.WriteFile(path, b, 0666)
  278. return nil
  279. }