This file is indexed.

/usr/share/gocode/src/github.com/ctdk/goiardi/serfin/serfin.go is in golang-github-ctdk-goiardi-dev 0.11.7-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Copyright (c) 2013-2017, Jeremy Bingham (<jeremy@goiardi.gl>)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package serfin bundles up serf functions for goiardi.
package serfin

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/ctdk/goiardi/config"
	serfclient "github.com/hashicorp/serf/client"
	"github.com/tideland/golib/logger"
	"sync"
	"time"
)

// Serfer is the common serf client for goiardi. NB: moving away from doing it
// this way.
var Serfer *serfclient.RPCClient

type serfClientMap struct {
	serfs map[string]*serfclient.RPCClient
	m     sync.Mutex
}

var serfClients *serfClientMap

func init() {
	serfClients = new(serfClientMap)
	serfClients.serfs = make(map[string]*serfclient.RPCClient)
}

func (scm *serfClientMap) addSerfClient(sc *serfclient.RPCClient, serfAddr string) {
	scm.m.Lock()
	defer scm.m.Unlock()
	scm.serfs[serfAddr] = sc
	return
}

func (scm *serfClientMap) closeAllSerfs() {
	scm.m.Lock()
	defer scm.m.Unlock()
	for addr, sc := range scm.serfs {
		sc.Close()
		delete(scm.serfs, addr)
	}
}

func (scm *serfClientMap) closeSerf(serfAddr string) {
	scm.m.Lock()
	defer scm.m.Unlock()
	if sc, ok := scm.serfs[serfAddr]; ok {
		sc.Close()
		delete(scm.serfs, serfAddr)
	}
}

// StartSerfin sets up the serf instance and starts listening for events and
// queries from other serf instances.
func StartSerfin() error {
	var err error
	Serfer, err = NewRPCClient(config.Config.SerfAddr)
	if err != nil {
		logger.Criticalf(err.Error())
		os.Exit(1)
	}

	if config.Config.SerfEventAnnounce {
		err = Serfer.UserEvent("goiardi-join", []byte(config.Config.Hostname), true)
		if err != nil {
			logger.Criticalf(err.Error())
			os.Exit(1)
		}
	}

	return nil
}

// Query makes a query to the default serf client, reconnecting if it's been
// closed.
func Query(q *serfclient.QueryParam, errch chan<- error) {
	var err error

	// retry connecting to serf for 5 minutes, every 5 seconds. TODO:
	// probably should make this configurable eventually.
	retryDelay := time.Duration(5)
	retryNum := 60

	if Serfer == nil || Serfer.IsClosed() {
		serfClients.closeSerf(config.Config.SerfAddr)
		var ns *serfclient.RPCClient
		for i := 0; i < retryNum; i++ {
			logger.Debugf("reconnecting to serf try #%d...", i+1)
			ns, err = NewRPCClient(config.Config.SerfAddr)
			if err == nil {
				Serfer = ns
				logger.Debugf("reconnected to serf!")
				break
			}
			logger.Debugf("Failed to reconnect to serf on try #%d, waiting %d seconds", i+1, retryDelay)
			time.Sleep(retryDelay * time.Second)
		}
		// if we got here we never managed to reconnect
		qErr := fmt.Errorf("Could not reconnect to serf after %d seconds. Last error: %s", int(retryDelay)*retryNum, err.Error())
		errch <- qErr
		close(errch)
		return
	}

	err = Serfer.Query(q)

	errch <- nil
	close(errch)
	return
}

func NewRPCClient(serfAddr string) (*serfclient.RPCClient, error) {
	sc, err := serfclient.NewRPCClient(serfAddr)
	if err != nil {
		return nil, err
	}
	serfClients.addSerfClient(sc, serfAddr)
	return sc, nil
}

// CloseAll closes all active serf clients
func CloseAll() {
	serfClients.closeAllSerfs()
}

// CloseSerfClient closes one serf client.
func CloseSerfClient(serfAddr string) {
	serfClients.closeSerf(serfAddr)
}

// SendEvent sends a serf event out from goiardi.
func SendEvent(eventName string, payload interface{}) {
	jsonPayload, err := json.Marshal(payload)
	if err != nil {
		logger.Errorf(err.Error())
		return
	}
	err = Serfer.UserEvent(eventName, jsonPayload, true)
	if err != nil {
		logger.Debugf(err.Error())
	}
	return
}

// SendQuery sends a basic, no frills query out over serf.
func SendQuery(queryName string, payload interface{}) {
	jsonPayload, err := json.Marshal(payload)
	if err != nil {
		logger.Errorf(err.Error())
		return
	}
	q := &serfclient.QueryParam{Name: queryName, Payload: jsonPayload}
	err = Serfer.Query(q)
	if err != nil {
		logger.Debugf(err.Error())
	}
	return
}