github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/gateway/redis_signal_handle_config.go (about)

     1  package gateway
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"os"
     7  	"syscall"
     8  	"time"
     9  
    10  	"github.com/sirupsen/logrus"
    11  
    12  	"github.com/TykTechnologies/tyk/config"
    13  )
    14  
    15  type ConfigPayload struct {
    16  	Configuration config.Config
    17  	ForHostname   string
    18  	ForNodeID     string
    19  	TimeStamp     int64
    20  }
    21  
    22  func backupConfiguration() error {
    23  	oldConfig, err := json.MarshalIndent(config.Global, "", "    ")
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	now := time.Now()
    29  	asStr := now.Format("Mon-Jan-_2-15-04-05-2006")
    30  	fName := asStr + ".tyk.conf"
    31  	return ioutil.WriteFile(fName, oldConfig, 0644)
    32  }
    33  
    34  func writeNewConfiguration(payload ConfigPayload) error {
    35  	newConfig, err := json.MarshalIndent(payload.Configuration, "", "    ")
    36  	if err != nil {
    37  		return err
    38  	}
    39  	return ioutil.WriteFile(confPaths[0], newConfig, 0644)
    40  }
    41  
    42  func handleNewConfiguration(payload string) {
    43  	// Decode the configuration from the payload
    44  	configPayload := ConfigPayload{}
    45  
    46  	// We actually want to merge into the existing configuration
    47  	// so as not to lose data through automatic defaults
    48  	config.Load(confPaths, &configPayload.Configuration)
    49  
    50  	err := json.Unmarshal([]byte(payload), &configPayload)
    51  	if err != nil {
    52  		log.WithFields(logrus.Fields{
    53  			"prefix": "pub-sub",
    54  		}).Error("Failed to decode configuration payload: ", err)
    55  		return
    56  	}
    57  
    58  	// Make sure payload matches nodeID and hostname
    59  	if configPayload.ForHostname != hostDetails.Hostname && configPayload.ForNodeID != GetNodeID() {
    60  		log.WithFields(logrus.Fields{
    61  			"prefix": "pub-sub",
    62  		}).Info("Configuration update received, no NodeID/Hostname match found")
    63  		return
    64  	}
    65  
    66  	if !config.Global().AllowRemoteConfig {
    67  		log.WithFields(logrus.Fields{
    68  			"prefix": "pub-sub",
    69  		}).Warning("Ignoring new config: Remote configuration is not allowed for this node.")
    70  		return
    71  	}
    72  
    73  	if err := backupConfiguration(); err != nil {
    74  		log.WithFields(logrus.Fields{
    75  			"prefix": "pub-sub",
    76  		}).Error("Failed to backup existing configuration: ", err)
    77  		return
    78  	}
    79  
    80  	if err := writeNewConfiguration(configPayload); err != nil {
    81  		log.WithFields(logrus.Fields{
    82  			"prefix": "pub-sub",
    83  		}).Error("Failed to write new configuration: ", err)
    84  		return
    85  	}
    86  
    87  	log.WithFields(logrus.Fields{
    88  		"prefix": "pub-sub",
    89  	}).Info("Initiating configuration reload")
    90  
    91  	myPID := hostDetails.PID
    92  	if myPID == 0 {
    93  		log.Error("No PID found, cannot reload")
    94  		return
    95  	}
    96  
    97  	log.Info("Sending reload signal to PID: ", myPID)
    98  	if err := syscall.Kill(myPID, syscall.SIGUSR2); err != nil {
    99  		log.Error("Process reload failed: ", err)
   100  	}
   101  }
   102  
   103  type GetConfigPayload struct {
   104  	FromHostname string
   105  	FromNodeID   string
   106  	TimeStamp    int64
   107  }
   108  
   109  type ReturnConfigPayload struct {
   110  	FromHostname  string
   111  	FromNodeID    string
   112  	Configuration map[string]interface{}
   113  	TimeStamp     int64
   114  }
   115  
   116  func sanitizeConfig(mc map[string]interface{}) map[string]interface{} {
   117  	sanitzeFields := []string{
   118  		"secret",
   119  		"node_secret",
   120  		"storage",
   121  		"slave_options",
   122  		"auth_override",
   123  	}
   124  	for _, field_name := range sanitzeFields {
   125  		delete(mc, field_name)
   126  	}
   127  	return mc
   128  }
   129  
   130  func getExistingConfig() (map[string]interface{}, error) {
   131  	f, err := os.Open(config.Global().OriginalPath)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	var microConfig map[string]interface{}
   136  	if err := json.NewDecoder(f).Decode(&microConfig); err != nil {
   137  		return nil, err
   138  	}
   139  	return sanitizeConfig(microConfig), nil
   140  }
   141  
   142  func handleSendMiniConfig(payload string) {
   143  	// Decode the configuration from the payload
   144  	configPayload := GetConfigPayload{}
   145  	err := json.Unmarshal([]byte(payload), &configPayload)
   146  	if err != nil {
   147  		log.WithFields(logrus.Fields{
   148  			"prefix": "pub-sub",
   149  		}).Error("Failed unmarshal request: ", err)
   150  		return
   151  	}
   152  
   153  	// Make sure payload matches nodeID and hostname
   154  	if configPayload.FromHostname != hostDetails.Hostname && configPayload.FromNodeID != GetNodeID() {
   155  		log.WithFields(logrus.Fields{
   156  			"prefix": "pub-sub",
   157  		}).Debug("Configuration request received, no NodeID/Hostname match found, ignoring")
   158  		return
   159  	}
   160  
   161  	config, err := getExistingConfig()
   162  	if err != nil {
   163  		log.WithFields(logrus.Fields{
   164  			"prefix": "pub-sub",
   165  		}).Error("Failed to get existing configuration: ", err)
   166  		return
   167  	}
   168  
   169  	returnPayload := ReturnConfigPayload{
   170  		FromHostname:  hostDetails.Hostname,
   171  		FromNodeID:    GetNodeID(),
   172  		Configuration: config,
   173  		TimeStamp:     time.Now().Unix(),
   174  	}
   175  
   176  	payloadAsJSON, err := json.Marshal(returnPayload)
   177  	if err != nil {
   178  		log.WithFields(logrus.Fields{
   179  			"prefix": "pub-sub",
   180  		}).Error("Failed to get marshal configuration: ", err)
   181  		return
   182  	}
   183  
   184  	asNotification := Notification{
   185  		Command: NoticeGatewayConfigResponse,
   186  		Payload: string(payloadAsJSON),
   187  	}
   188  
   189  	MainNotifier.Notify(asNotification)
   190  	log.WithFields(logrus.Fields{
   191  		"prefix": "pub-sub",
   192  	}).Debug("Configuration request responded.")
   193  
   194  }