|
|
//LEAPI - ACME Certificate Renewal Control API - Copyright 2022-2024 Ruel Tmeizeh All Rights Reserved
|
|
|
package main
|
|
|
|
|
|
import (
|
|
|
"crypto/tls"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"io/ioutil"
|
|
|
"log"
|
|
|
"net/http"
|
|
|
"strconv"
|
|
|
"sync"
|
|
|
)
|
|
|
|
|
|
func syncAllServers() error {
|
|
|
var theError error
|
|
|
numservers := len(servers)
|
|
|
c := make(chan string)
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
wg.Add(numservers)
|
|
|
for n := 0; n < numservers; n++ {
|
|
|
go func(c chan string) {
|
|
|
for {
|
|
|
srv, more := <-c
|
|
|
if more == false {
|
|
|
wg.Done()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
log.Println("Parallel execution sync of server: " + srv + "...")
|
|
|
err := syncOneServer(srv)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
theError = err
|
|
|
}
|
|
|
}
|
|
|
}(c)
|
|
|
}
|
|
|
for _, server := range servers { //send each server to the channel
|
|
|
if server == appconf.Hostname { //don't send myself
|
|
|
continue
|
|
|
}
|
|
|
c <- server
|
|
|
}
|
|
|
close(c)
|
|
|
wg.Wait()
|
|
|
log.Println("Finished sending sync requests.")
|
|
|
|
|
|
return theError //if any one or more fail, return an error for it (the last one that fails)
|
|
|
}
|
|
|
|
|
|
func syncOneServer(server string) error {
|
|
|
//Make http requests to each other servers' /sync endpoints
|
|
|
// https://server.tld:port/sync
|
|
|
log.Println("SYNC " + server + " starting...")
|
|
|
req, err := http.NewRequest("POST", syncScheme+server+":"+syncPort+"/api/sync/"+appconf.Hostname, nil)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't create new HTTP sync request for server: " + server)
|
|
|
}
|
|
|
req.Close = true
|
|
|
req.Header.Set("User-Agent", myUserAgent)
|
|
|
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
|
|
|
//skip verification of cert for https syncing, since the cert may not be setup properly at first
|
|
|
customTransport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
|
client := &http.Client{Transport: customTransport, Timeout: timeout}
|
|
|
//client := &http.Client{Timeout: timeout}
|
|
|
response, err := client.Do(req)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't perform HTTP sync request to server: " + server)
|
|
|
}
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't parse response body on request to server: " + server)
|
|
|
}
|
|
|
if response.StatusCode != 200 {
|
|
|
errorString := "Problem syncing to server " + server + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body)
|
|
|
log.Println(errorString)
|
|
|
return errors.New(errorString)
|
|
|
}
|
|
|
log.Println("SYNC " + server + " success!")
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func syncServersFromHost(host string) error {
|
|
|
var theError error
|
|
|
req, err := http.NewRequest("GET", syncScheme+host+":"+syncPort+"/api/servers", nil)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't create new HTTP request for syncing servers from host: " + host)
|
|
|
}
|
|
|
req.Close = true
|
|
|
req.Header.Set("User-Agent", myUserAgent)
|
|
|
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
|
|
|
//skip verification of cert for https syncing, since the cert may not be setup properly at first
|
|
|
customTransport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
|
client := &http.Client{Transport: customTransport, Timeout: timeout}
|
|
|
//client := &http.Client{Timeout: timeout}
|
|
|
response, err := client.Do(req)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't perform HTTP server sync request to host: " + host)
|
|
|
}
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't parse response body from server sync request to server: " + host)
|
|
|
}
|
|
|
if response.StatusCode != 200 {
|
|
|
theError = errors.New("Problem syncing servers from host " + host + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body))
|
|
|
log.Println(theError.Error())
|
|
|
return theError
|
|
|
}
|
|
|
|
|
|
var result APIOutput
|
|
|
err = json.Unmarshal(body, &result)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't parse response body from host " + host + ": " + err.Error())
|
|
|
}
|
|
|
servers = result.Data
|
|
|
|
|
|
err = writeServers()
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func syncDomainsFromHost(host string) error {
|
|
|
var theError error
|
|
|
req, err := http.NewRequest("GET", syncScheme+host+":"+syncPort+"/api/domains", nil)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't create new HTTP request for syncing domains from host: " + host)
|
|
|
}
|
|
|
req.Close = true
|
|
|
req.Header.Set("User-Agent", myUserAgent)
|
|
|
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
|
|
|
//skip verification of cert for https syncing, since the cert may not be setup properly at first
|
|
|
customTransport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
|
client := &http.Client{Transport: customTransport, Timeout: timeout}
|
|
|
//client := &http.Client{Timeout: timeout}
|
|
|
response, err := client.Do(req)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't perform HTTP domain sync request to host: " + host)
|
|
|
}
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't parse response body from domain sync request to server: " + host)
|
|
|
}
|
|
|
if response.StatusCode != 200 {
|
|
|
theError = errors.New("Problem syncing domains from host " + host + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body))
|
|
|
log.Println(theError.Error())
|
|
|
return theError
|
|
|
}
|
|
|
|
|
|
var result APIOutput
|
|
|
err = json.Unmarshal(body, &result)
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return errors.New("Couldn't parse response body from host " + host + ": " + err.Error())
|
|
|
}
|
|
|
domains = result.Data
|
|
|
|
|
|
err = writeDomains()
|
|
|
if err != nil {
|
|
|
log.Println(err.Error())
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|