mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
all: add sending logs to ControlD API
This commit is contained in:
committed by
Cuong Manh Le
parent
f5ba8be182
commit
a63a30c76b
@@ -1269,7 +1269,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
|
||||
|
||||
cdLogger := mainLog.Load().With().Str("mode", "cd").Logger()
|
||||
// Performs self-uninstallation if the ControlD device does not exist.
|
||||
var uer *controld.UtilityErrorResponse
|
||||
var uer *controld.ErrorResponse
|
||||
if errors.As(err, &uer) && uer.ErrorField.Code == controld.InvalidConfigCode {
|
||||
_ = uninstallInvalidCdUID(p, cdLogger, false)
|
||||
}
|
||||
|
||||
@@ -1044,7 +1044,7 @@ func dnsChanged(iface *net.Interface, nameservers []string) bool {
|
||||
|
||||
// selfUninstallCheck checks if the error dues to controld.InvalidConfigCode, perform self-uninstall then.
|
||||
func selfUninstallCheck(uninstallErr error, p *prog, logger zerolog.Logger) {
|
||||
var uer *controld.UtilityErrorResponse
|
||||
var uer *controld.ErrorResponse
|
||||
if errors.As(uninstallErr, &uer) && uer.ErrorField.Code == controld.InvalidConfigCode {
|
||||
p.stopDnsWatchers()
|
||||
|
||||
|
||||
@@ -25,8 +25,12 @@ import (
|
||||
const (
|
||||
apiDomainCom = "api.controld.com"
|
||||
apiDomainDev = "api.controld.dev"
|
||||
resolverDataURLCom = "https://api.controld.com/utility"
|
||||
resolverDataURLDev = "https://api.controld.dev/utility"
|
||||
apiURLCom = "https://api.controld.com"
|
||||
apiURLDev = "https://api.controld.dev"
|
||||
resolverDataURLCom = apiURLCom + "/utility"
|
||||
resolverDataURLDev = apiURLDev + "/utility"
|
||||
logURLCom = apiURLCom + "/logs"
|
||||
logURLDev = apiURLDev + "/logs"
|
||||
InvalidConfigCode = 40402
|
||||
)
|
||||
|
||||
@@ -49,14 +53,14 @@ type utilityResponse struct {
|
||||
} `json:"body"`
|
||||
}
|
||||
|
||||
type UtilityErrorResponse struct {
|
||||
type ErrorResponse struct {
|
||||
ErrorField struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
func (u UtilityErrorResponse) Error() string {
|
||||
func (u ErrorResponse) Error() string {
|
||||
return u.ErrorField.Message
|
||||
}
|
||||
|
||||
@@ -71,6 +75,12 @@ type UtilityOrgRequest struct {
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
// LogsRequest contains request data for sending runtime logs to API.
|
||||
type LogsRequest struct {
|
||||
UID string `json:"uid"`
|
||||
LogFile string `json:"log_file"`
|
||||
}
|
||||
|
||||
// FetchResolverConfig fetch Control D config for given uid.
|
||||
func FetchResolverConfig(rawUID, version string, cdDev bool) (*ResolverConfig, error) {
|
||||
uid, clientID := ParseRawUID(rawUID)
|
||||
@@ -123,6 +133,81 @@ func postUtilityAPI(version string, cdDev, lastUpdatedFailed bool, body io.Reade
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
transport := apiTransport(cdDev)
|
||||
client := http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("postUtilityAPI client.Do: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
d := json.NewDecoder(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errResp := &ErrorResponse{}
|
||||
if err := d.Decode(errResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errResp
|
||||
}
|
||||
|
||||
ur := &utilityResponse{}
|
||||
if err := d.Decode(ur); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ur.Body.Resolver, nil
|
||||
}
|
||||
|
||||
// SendLogs sends runtime log to ControlD API.
|
||||
func SendLogs(req *LogsRequest, cdDev bool) error {
|
||||
body, _ := json.Marshal(req)
|
||||
return postLogAPI(cdDev, bytes.NewReader(body))
|
||||
}
|
||||
|
||||
func postLogAPI(cdDev bool, body io.Reader) error {
|
||||
apiUrl := logURLCom
|
||||
if cdDev {
|
||||
apiUrl = logURLDev
|
||||
}
|
||||
req, err := http.NewRequest("POST", apiUrl, body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("http.NewRequest: %w", err)
|
||||
}
|
||||
transport := apiTransport(cdDev)
|
||||
client := http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("postLogAPI client.Do: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
d := json.NewDecoder(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errResp := &ErrorResponse{}
|
||||
if err := d.Decode(errResp); err != nil {
|
||||
return err
|
||||
}
|
||||
return errResp
|
||||
}
|
||||
_, _ = io.Copy(io.Discard, resp.Body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseRawUID parse the input raw UID, returning real UID and ClientID.
|
||||
// The raw UID can have 2 forms:
|
||||
//
|
||||
// - <uid>
|
||||
// - <uid>/<client_id>
|
||||
func ParseRawUID(rawUID string) (string, string) {
|
||||
uid, clientID, _ := strings.Cut(rawUID, "/")
|
||||
return uid, clientID
|
||||
}
|
||||
|
||||
// apiTransport returns an HTTP transport for connecting to ControlD API endpoint.
|
||||
func apiTransport(cdDev bool) *http.Transport {
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
apiDomain := apiDomainCom
|
||||
@@ -143,41 +228,8 @@ func postUtilityAPI(version string, cdDev, lastUpdatedFailed bool, body io.Reade
|
||||
d := &ctrldnet.ParallelDialer{}
|
||||
return d.DialContext(ctx, network, addrs)
|
||||
}
|
||||
|
||||
if router.Name() == ddwrt.Name || runtime.GOOS == "android" {
|
||||
transport.TLSClientConfig = &tls.Config{RootCAs: certs.CACertPool()}
|
||||
}
|
||||
client := http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("client.Do: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
d := json.NewDecoder(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errResp := &UtilityErrorResponse{}
|
||||
if err := d.Decode(errResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errResp
|
||||
}
|
||||
|
||||
ur := &utilityResponse{}
|
||||
if err := d.Decode(ur); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ur.Body.Resolver, nil
|
||||
}
|
||||
|
||||
// ParseRawUID parse the input raw UID, returning real UID and ClientID.
|
||||
// The raw UID can have 2 forms:
|
||||
//
|
||||
// - <uid>
|
||||
// - <uid>/<client_id>
|
||||
func ParseRawUID(rawUID string) (string, string) {
|
||||
uid, clientID, _ := strings.Cut(rawUID, "/")
|
||||
return uid, clientID
|
||||
return transport
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user