// main entry point for data writer func main() { var err error var writerSocket *zmq4.Socket var eventSubSocket *zmq4.Socket fog.Info("program starts") if writerSocket, err = createWriterSocket(); err != nil { fog.Critical("createWriterSocket %s", err) } defer writerSocket.Close() fog.Info("binding writer socket to %s", dataWriterAddress) if err = writerSocket.Bind(dataWriterAddress); err != nil { fog.Critical("Bind(%s) %s", dataWriterAddress, err) } if eventSubSocket, err = createEventSubSocket(); err != nil { fog.Critical("createEventSubSocket %s", err) } defer eventSubSocket.Close() fog.Info("connecting event sub socket to %s", eventAggregatorPubAddress) if err = eventSubSocket.Connect(eventAggregatorPubAddress); err != nil { fog.Critical("Connect(%s) %s", eventAggregatorPubAddress, err) } messageChan := NewMessageHandler() reactor := zmq4.NewReactor() reactor.AddChannel(tools.NewSignalWatcher(), 1, tools.SigtermHandler) reactor.AddSocket(writerSocket, zmq4.POLLIN, NewWriterSocketHandler(writerSocket, messageChan)) reactor.AddSocket(eventSubSocket, zmq4.POLLIN, NewEventSubSocketHandler(eventSubSocket)) fog.Debug("starting reactor.Run") reactor.SetVerbose(true) err = reactor.Run(reactorPollingInterval) if err == tools.SigtermError { fog.Info("program terminates normally due to SIGTERM") } else if errno, ok := err.(syscall.Errno); ok { // we can get 'interrupted system call' if we get SIGTERM while // a socket is waiting on a read. That's not too bad. if errno == syscall.EINTR { fog.Warn("reactor.Run returns '%s' assuming SIGTERM", errno) } else { fog.Error("reactor.Run returns %T '%s'", errno, errno) } } else { fog.Error("reactor.Run returns %T %s", err, err) } }
func testPOST(serviceDomain string, useTLS bool) { var contentLength uint64 = 1024 * 1024 * 1024 fog.Debug("start post %dmb", contentLength/(1024*1024)) client, scheme := getClient(useTLS) url := fmt.Sprintf("%s://%s/admin", scheme, serviceDomain) bodyReader := tools.NewSizeReader(contentLength) request, err := http.NewRequest("POST", url, bodyReader) if err != nil { fog.Critical("NewRequest (POST) failed %s", err) } request.TransferEncoding = []string{"identity"} request.Header.Add("Content-Type", "text/plain") request.Header.Add("Content-Length", fmt.Sprintf("%s", contentLength)) request.ContentLength = int64(contentLength) response, err := client.Do(request) if err != nil { fog.Error("post %s", err) return } tools.ReadAndDiscard(response.Body) response.Body.Close() fog.Debug("finished post %s", response.Status) }
// NewEventSubSocketHandler returns a function that handles event notifications func NewEventSubSocketHandler(eventSubSocket *zmq4.Socket) func(zmq4.State) error { var nodeIDMap map[string]uint32 var err error if nodeIDMap, err = centraldb.GetNodeIDMap(); err != nil { fog.Critical("centraldb.GetNodeIDMap() failed %s", err) } return func(_ zmq4.State) error { var err error var ok bool var webWriterStart msg.WebWriterStart var timestamp time.Time var sourceNodeID uint32 marshalledMessage, err := eventSubSocket.RecvMessage(0) if err != nil { return fmt.Errorf("RecvMessage %s", err) } // the 0th part should be the topic, we skip that err = json.Unmarshal([]byte(marshalledMessage[1]), &webWriterStart) if err != nil { return fmt.Errorf("Unmarshal %s", err) } if webWriterStart.MessageType != "web-writer-start" { return fmt.Errorf("unknown message type '%s'", webWriterStart.MessageType) } timestamp, err = tools.ParseTimestampRepr(webWriterStart.TimestampRepr) if err != nil { return fmt.Errorf("unable to parse %s %s", webWriterStart.TimestampRepr, err) } sourceNodeID, ok = nodeIDMap[webWriterStart.SourceNodeName] if !ok { return fmt.Errorf("unknown source_node_name %s", webWriterStart.SourceNodeName) } fog.Debug("cancel-segments-from-node %s", webWriterStart.SourceNodeName) // cancel all all segment rows // * from a specifiic source node // * are in active status // * with a timestamp earlier than the specified time. // This is triggered by a web server restart stmt := nodedb.Stmts["cancel-segments-from-node"] if _, err = stmt.Exec(sourceNodeID, timestamp); err != nil { return fmt.Errorf("cancel-segments-from-node %s", err) } return nil } }
func NewMessageHandler() chan<- types.Message { var nimbusioWriter writer.NimbusioWriter var replyChan chan<- *reply.ReplyMessage var err error messageChan := make(chan types.Message, messageChanCapacity) if err = nodedb.Initialize(); err != nil { fog.Critical("NewMessageHandler: nodedb.Initialize failed %s", err) } if nimbusioWriter, err = writer.NewNimbusioWriter(); err != nil { fog.Critical("NewMessageHandler: NewNimbusioWriter() failed %s", err) } replyChan = reply.NewReplyHandler() dispatchTable := map[string]messageHandler{ "archive-key-entire": handleArchiveKeyEntire, "archive-key-start": handleArchiveKeyStart, "archive-key-next": handleArchiveKeyNext, "archive-key-final": handleArchiveKeyFinal, "archive-key-cancel": handleArchiveKeyCancel, "destroy-key": handleDestroyKey, "start-conjoined-archive": handleStartConjoinedArchive, "abort-conjoined-archive": handleAbortConjoinedArchive, "finish-conjoined-archive": handleFinishConjoinedArchive} go func() { for message := range messageChan { handler, ok := dispatchTable[message.Type] if !ok { fog.Error("Unknown message type %s %s", message.Type, message.Marshalled) continue } go handler(message, nimbusioWriter, replyChan) } }() return messageChan }
func init() { destHashKey = make([]byte, keySize) keyPath := os.Getenv("NIMBUSIO_URL_DEST_HASH_KEY") if keyPath != "" { file, err := os.Open(keyPath) if err != nil { fog.Critical("No valid file at NIMBUSIO_URL_DEST_HASH_KEY %s %s", keyPath, err) } defer file.Close() _, err = file.Read(destHashKey) if err != nil { fog.Critical("Error reading file at NIMBUSIO_URL_DEST_HASH_KEY %s %s", keyPath, err) } } else { _, err := rand.Read(destHashKey) if err != nil { fog.Critical("Error reading destHashKey rand.Read %s", err) } } }
func init() { maxValueFileSizeStr := os.Getenv("NIMBUS_IO_MAX_VALUE_FILE_SIZE") if maxValueFileSizeStr == "" { MaxValueFileSize = uint64(1024 * 1024 * 1024) } else { var intSize int var err error intSize, err = strconv.Atoi(maxValueFileSizeStr) if err != nil { fog.Critical("invalid NIMBUS_IO_MAX_VALUE_FILE_SIZE '%s'", maxValueFileSizeStr) } MaxValueFileSize = uint64(intSize) } }
func testGET(serviceDomain string, useTLS bool) { fog.Debug("start get") client, scheme := getClient(useTLS) url := fmt.Sprintf("%s://%s/admin", scheme, serviceDomain) request, err := http.NewRequest("GET", url, nil) if err != nil { fog.Critical("NewRequest (GET) failed %s", err) } response, err := client.Do(request) if err != nil { fog.Error("get %s", err) return } fog.Debug("reading GET response body") tools.ReadAndDiscard(response.Body) response.Body.Close() fog.Debug("finished get %s", response.Status) }
// Critical prepends literal 'CRITICAL' to log message // program terminates func (l logData) Critical(text string, args ...interface{}) { fog.Critical(l.prefix()+text, args...) }
// main entry point for webdirector func main() { var err error fog.Info("program starts") // set up a signal handling channel signalChannel := make(chan os.Signal) signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) if profilePath := os.Getenv("WEBDIRECTOR_CPU_PROFILE_PATH"); profilePath != "" { profileFile, err := os.Create(profilePath) if err != nil { fog.Critical("os.Create(%s) failed %s", profilePath, err) } fog.Info("writing CPU profile data to %s", profilePath) pprof.StartCPUProfile(profileFile) defer pprof.StopCPUProfile() } useTLS := os.Getenv("NIMBUS_IO_SERVICE_SSL") == "1" fog.Info("TLS = %t", useTLS) listenAddress, err := getListenAddress() if err != nil { fog.Critical("error getListenAddress %s", err) } fog.Info("webdirector listens to %s", listenAddress) var listener net.Listener if useTLS { if listener, err = getTLSListener(listenAddress); err != nil { fog.Critical("Unable to create TLS listener: %s", err) } } else { if listener, err = getTCPListener(listenAddress); err != nil { fog.Critical("Unable to create TCP listener: %s", err) } } managmentAPIDests, err := mgmtapi.NewManagementAPIDestinations() if err != nil { fog.Critical("NewManagementAPIDestinations: %s", err) } centralDB := centraldb.NewCentralDB() availableHosts, err := avail.NewAvailability() if err != nil { fog.Critical("NewAvailability: %s", err) } router := routing.NewRouter(managmentAPIDests, centralDB, availableHosts) fog.Info("NIMBUS_IO_SERVICE_DOMAIN = '%s'", os.Getenv("NIMBUS_IO_SERVICE_DOMAIN")) fog.Info("NIMBUSIO_WEB_PUBLIC_READER_PORT = '%s'", os.Getenv("NIMBUSIO_WEB_PUBLIC_READER_PORT")) fog.Info("NIMBUSIO_WEB_WRITER_PORT = '%s'", os.Getenv("NIMBUSIO_WEB_WRITER_PORT")) listenerChan := make(chan net.Conn, listenerChanCapacity) go func() { for { connection, err := listener.Accept() if err != nil { fog.Error("listener.Accept() %s", err) close(listenerChan) break } listenerChan <- connection } }() for running := true; running; { select { case signal := <-signalChannel: fog.Info("terminated by signal: %v", signal) running = false case conn, ok := <-listenerChan: if ok { fog.Info("connection from %s", conn.RemoteAddr().String()) go handleConnection(router, conn) } else { running = false } } } listener.Close() fog.Info("program terminates") }