1 package entrypoint
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "io/ioutil"
8 "net/http"
9 "net/url"
10 "syscall"
11 "time"
12
13 "github.com/emissary-ingress/emissary/v3/pkg/acp"
14 "github.com/emissary-ingress/emissary/v3/pkg/debug"
15
16 "github.com/datawire/dlib/dlog"
17 )
18
19 type notable interface {
20 NoteSnapshotSent()
21 NoteSnapshotProcessed()
22 }
23
24 type noopNotable struct{}
25
26 func (_ *noopNotable) NoteSnapshotSent() {}
27 func (_ *noopNotable) NoteSnapshotProcessed() {}
28
29 func notifyReconfigWebhooks(ctx context.Context, ambwatch notable) error {
30 isEdgeStack, err := IsEdgeStack()
31 if err != nil {
32 return err
33 }
34 return notifyReconfigWebhooksFunc(ctx, ambwatch, isEdgeStack)
35 }
36
37 func notifyReconfigWebhooksFunc(ctx context.Context, ambwatch notable, edgestack bool) error {
38
39 snapshotUrl := url.QueryEscape("http://localhost:9696/snapshot")
40
41 needDiagdNotify := true
42 needSidecarNotify := true
43
44
45
46
47 ambwatch.NoteSnapshotSent()
48
49 for {
50
51 finished, err := notifyWebhookUrl(ctx, "diagd", fmt.Sprintf("%s?url=%s", GetEventUrl(), snapshotUrl))
52 if err != nil {
53 return err
54 }
55 if finished {
56 needDiagdNotify = false
57
58
59
60 ambwatch.NoteSnapshotProcessed()
61 }
62
63
64 if edgestack {
65 finished, err := notifyWebhookUrl(ctx, "edgestack sidecar", fmt.Sprintf("%s?url=%s", GetSidecarUrl(), snapshotUrl))
66 if err != nil {
67 return err
68 }
69 if finished {
70 needSidecarNotify = false
71 }
72 } else {
73 needSidecarNotify = false
74 }
75
76 select {
77 case <-ctx.Done():
78 return nil
79 default:
80
81 if needDiagdNotify || needSidecarNotify {
82 time.Sleep(1 * time.Second)
83 } else {
84 return nil
85 }
86 }
87 }
88 }
89
90
91 func notifyWebhookUrl(ctx context.Context, name, xurl string) (bool, error) {
92 defer debug.FromContext(ctx).Timer(fmt.Sprintf("notifyWebhook:%s", name)).Start()()
93
94 req, err := http.NewRequestWithContext(ctx, http.MethodPost, xurl, nil)
95 if err != nil {
96 return false, err
97 }
98
99
100
101
102 parsedURL, err := url.Parse(xurl)
103 if err != nil {
104
105
106 panic(fmt.Errorf("BUG: bad URL passed to notifyWebhookUrl: '%s', %v", xurl, err))
107 }
108
109
110
111
112
113 if acp.HostPortIsLocal(fmt.Sprintf("%s:%s", parsedURL.Hostname(), parsedURL.Port())) {
114
115 req.Header.Set("X-Ambassador-Diag-IP", "127.0.0.1")
116 }
117
118 req.Header.Set("content-type", "application/json")
119 resp, err := http.DefaultClient.Do(req)
120 if err != nil {
121 if errors.Is(err, syscall.ECONNREFUSED) {
122
123
124 dlog.Error(ctx, err.Error())
125 return false, nil
126 } else {
127
128
129
130
131 return false, err
132 }
133 }
134 defer resp.Body.Close()
135
136 if resp.StatusCode != 200 {
137 body, err := ioutil.ReadAll(resp.Body)
138 if err != nil {
139 dlog.Printf(ctx, "error reading body from %s: %v", name, err)
140 } else {
141 dlog.Printf(ctx, "error notifying %s: %s, %s", name, resp.Status, string(body))
142 }
143 }
144
145
146
147
148 return true, nil
149 }
150
View as plain text