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  }