//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 }