github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/dashboard_register.go (about) 1 package gateway 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "net/http" 10 "time" 11 12 "github.com/TykTechnologies/tyk/config" 13 "github.com/TykTechnologies/tyk/headers" 14 ) 15 16 var dashLog = log.WithField("prefix", "dashboard") 17 18 type NodeResponseOK struct { 19 Status string 20 Message map[string]string 21 Nonce string 22 } 23 24 type DashboardServiceSender interface { 25 Init() error 26 Register() error 27 DeRegister() error 28 StartBeating() error 29 StopBeating() 30 NotifyDashboardOfEvent(interface{}) error 31 } 32 33 type HTTPDashboardHandler struct { 34 RegistrationEndpoint string 35 DeRegistrationEndpoint string 36 HeartBeatEndpoint string 37 KeyQuotaTriggerEndpoint string 38 39 Secret string 40 41 heartBeatStopSentinel bool 42 } 43 44 func initialiseClient(timeout time.Duration) *http.Client { 45 client := &http.Client{ 46 Timeout: timeout, 47 } 48 49 if config.Global().HttpServerOptions.UseSSL { 50 // Setup HTTPS client 51 tlsConfig := &tls.Config{ 52 InsecureSkipVerify: config.Global().HttpServerOptions.SSLInsecureSkipVerify, 53 } 54 55 client.Transport = &http.Transport{TLSClientConfig: tlsConfig} 56 } 57 58 return client 59 } 60 61 func reLogin() { 62 if !config.Global().UseDBAppConfigs { 63 return 64 } 65 66 dashLog.Info("Registering node (again).") 67 DashService.StopBeating() 68 if err := DashService.DeRegister(); err != nil { 69 dashLog.Error("Could not deregister: ", err) 70 } 71 72 time.Sleep(5 * time.Second) 73 74 if err := DashService.Register(); err != nil { 75 dashLog.Error("Could not register: ", err) 76 } else { 77 go DashService.StartBeating() 78 } 79 80 dashLog.Info("Recovering configurations, reloading...") 81 reloadURLStructure(nil) 82 } 83 84 func (h *HTTPDashboardHandler) Init() error { 85 h.RegistrationEndpoint = buildConnStr("/register/node") 86 h.DeRegistrationEndpoint = buildConnStr("/system/node") 87 h.HeartBeatEndpoint = buildConnStr("/register/ping") 88 h.KeyQuotaTriggerEndpoint = buildConnStr("/system/key/quota_trigger") 89 90 if h.Secret = config.Global().NodeSecret; h.Secret == "" { 91 dashLog.Fatal("Node secret is not set, required for dashboard connection") 92 } 93 return nil 94 } 95 96 // NotifyDashboardOfEvent acts as a form of event which informs the 97 // dashboard of a key which has reached a certain usage quota 98 func (h *HTTPDashboardHandler) NotifyDashboardOfEvent(event interface{}) error { 99 100 meta, ok := event.(EventTriggerExceededMeta) 101 if !ok { 102 return errors.New("event type is currently not supported as a notification to the dashboard") 103 } 104 105 var b bytes.Buffer 106 if err := json.NewEncoder(&b).Encode(meta); err != nil { 107 log.Errorf("Could not decode event metadata :%v", err) 108 return err 109 } 110 111 req, err := http.NewRequest(http.MethodPost, h.KeyQuotaTriggerEndpoint, &b) 112 if err != nil { 113 log.Errorf("Could not create request.. %v", err) 114 return err 115 } 116 117 req.Header.Set("authorization", h.Secret) 118 req.Header.Set(headers.XTykNodeID, getNodeID()) 119 req.Header.Set(headers.XTykNonce, ServiceNonce) 120 121 c := initialiseClient(5 * time.Second) 122 123 resp, err := c.Do(req) 124 if err != nil { 125 log.Errorf("Request failed with error %v", err) 126 return err 127 } 128 129 defer resp.Body.Close() 130 131 if resp.StatusCode != http.StatusOK { 132 err := fmt.Errorf("Unexpected status code while trying to notify dashboard of a key limit quota trigger.. Got %d", resp.StatusCode) 133 log.Error(err) 134 return err 135 } 136 137 val := NodeResponseOK{} 138 if err := json.NewDecoder(resp.Body).Decode(&val); err != nil { 139 return err 140 } 141 142 ServiceNonce = val.Nonce 143 144 return nil 145 } 146 147 func (h *HTTPDashboardHandler) Register() error { 148 dashLog.Info("Registering gateway node with Dashboard") 149 req := h.newRequest(h.RegistrationEndpoint) 150 c := initialiseClient(5 * time.Second) 151 resp, err := c.Do(req) 152 153 if err != nil { 154 dashLog.Errorf("Request failed with error %v; retrying in 5s", err) 155 time.Sleep(time.Second * 5) 156 return h.Register() 157 } else if resp != nil && resp.StatusCode != 200 { 158 dashLog.Errorf("Response failed with code %d; retrying in 5s", resp.StatusCode) 159 time.Sleep(time.Second * 5) 160 return h.Register() 161 } 162 163 defer resp.Body.Close() 164 val := NodeResponseOK{} 165 if err := json.NewDecoder(resp.Body).Decode(&val); err != nil { 166 return err 167 } 168 169 // Set the NodeID 170 var found bool 171 nodeID, found := val.Message["NodeID"] 172 setNodeID(nodeID) 173 if !found { 174 dashLog.Error("Failed to register node, retrying in 5s") 175 time.Sleep(time.Second * 5) 176 return h.Register() 177 } 178 179 dashLog.WithField("id", getNodeID()).Info("Node Registered") 180 181 // Set the nonce 182 ServiceNonce = val.Nonce 183 dashLog.Debug("Registration Finished: Nonce Set: ", ServiceNonce) 184 185 return nil 186 } 187 188 func (h *HTTPDashboardHandler) StartBeating() error { 189 190 req := h.newRequest(h.HeartBeatEndpoint) 191 192 client := initialiseClient(5 * time.Second) 193 194 for !h.heartBeatStopSentinel { 195 if err := h.sendHeartBeat(req, client); err != nil { 196 dashLog.Warning(err) 197 } 198 time.Sleep(time.Second * 2) 199 } 200 201 dashLog.Info("Stopped Heartbeat") 202 h.heartBeatStopSentinel = false 203 return nil 204 } 205 206 func (h *HTTPDashboardHandler) StopBeating() { 207 h.heartBeatStopSentinel = true 208 } 209 210 func (h *HTTPDashboardHandler) newRequest(endpoint string) *http.Request { 211 req, err := http.NewRequest("GET", endpoint, nil) 212 if err != nil { 213 panic(err) 214 } 215 req.Header.Set("authorization", h.Secret) 216 req.Header.Set(headers.XTykHostname, hostDetails.Hostname) 217 return req 218 } 219 220 func (h *HTTPDashboardHandler) sendHeartBeat(req *http.Request, client *http.Client) error { 221 req.Header.Set(headers.XTykNodeID, getNodeID()) 222 req.Header.Set(headers.XTykNonce, ServiceNonce) 223 224 resp, err := client.Do(req) 225 if err != nil { 226 return errors.New("dashboard is down? Heartbeat is failing") 227 } 228 229 defer resp.Body.Close() 230 if resp.StatusCode != http.StatusOK { 231 return errors.New("dashboard is down? Heartbeat non-200 response") 232 } 233 val := NodeResponseOK{} 234 if err := json.NewDecoder(resp.Body).Decode(&val); err != nil { 235 return err 236 } 237 238 // Set the nonce 239 ServiceNonce = val.Nonce 240 //log.Debug("Heartbeat Finished: Nonce Set: ", ServiceNonce) 241 242 return nil 243 } 244 245 func (h *HTTPDashboardHandler) DeRegister() error { 246 req := h.newRequest(h.DeRegistrationEndpoint) 247 248 req.Header.Set(headers.XTykNodeID, getNodeID()) 249 req.Header.Set(headers.XTykNonce, ServiceNonce) 250 251 c := initialiseClient(5 * time.Second) 252 resp, err := c.Do(req) 253 254 if err != nil { 255 return fmt.Errorf("deregister request failed with error %v", err) 256 } 257 defer resp.Body.Close() 258 if resp.StatusCode != http.StatusOK { 259 return fmt.Errorf("deregister request failed with status %v", resp.StatusCode) 260 } 261 262 val := NodeResponseOK{} 263 if err := json.NewDecoder(resp.Body).Decode(&val); err != nil { 264 return err 265 } 266 267 // Set the nonce 268 ServiceNonce = val.Nonce 269 dashLog.Info("De-registered.") 270 271 return nil 272 }