main.go 5.49 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
2
3
4
5
6
7
8
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
Lukas Burgey's avatar
Lukas Burgey committed
9
	"os"
10
	"time"
Lukas Burgey's avatar
Lukas Burgey committed
11

Lukas Burgey's avatar
Lukas Burgey committed
12
	"gopkg.in/alecthomas/kingpin.v2"
Lukas Burgey's avatar
Lukas Burgey committed
13
14
)

Lukas Burgey's avatar
Lukas Burgey committed
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
type (
	rabbitMQConfig struct {
		ExchangeName string `json:"exchange"`
		Vhost        string `json:"vhost"`
	}

	fetchedConfig struct {
		RabbitMQConfig rabbitMQConfig `json:"rabbitmq_config"`
		Services       []service      `json:"services"`
	}

	config struct {
		Host                   string             `json:"host"`
		Username               string             `json:"username"`
		Password               string             `json:"password"`
		Services               map[string]service `json:"services"`
		FetchIntervalString    string             `json:"fetch_interval"`    // string parsed by time.ParseDuration
		ReconnectTimeoutString string             `json:"reconnect_timeout"` // string parsed by time.ParseDuration
		NewTasks               chan task
		DoneTasks              chan task
		FetchInterval          time.Duration
		ReconnectTimeout       time.Duration

		ExchangeName string // fetched from backend
		Vhost        string // fetched  from backend
	}
)

Lukas Burgey's avatar
Lukas Burgey committed
43
44
45
46
const (
	version = "0.1.0"
)

Lukas Burgey's avatar
Lukas Burgey committed
47
var (
Lukas Burgey's avatar
Lukas Burgey committed
48
	client = &http.Client{}
Lukas Burgey's avatar
Lukas Burgey committed
49
50
)

51
func logError(err error, msg string) {
Lukas Burgey's avatar
Lukas Burgey committed
52
	if err != nil {
53
		log.Printf("[E] %s: %s", msg, err)
Lukas Burgey's avatar
Lukas Burgey committed
54
55
56
	}
}

Lukas Burgey's avatar
Lukas Burgey committed
57
58
59
60
61
62
63
64
func (s service) String() string {
	return s.Name
}

func (t task) String() string {
	return fmt.Sprintf("%s:%s %8s %s", t.Service, t.User, t.Action, t.Key)
}

65
func (c *config) fetchConfig() (err error) {
Lukas Burgey's avatar
Lukas Burgey committed
66
67
68
69
70
	req, err := http.NewRequest("GET", "https://"+c.Host+"/backend/clientapi/config", nil)
	if err != nil {
		return
	}

71
	req.SetBasicAuth(c.Username, c.Password)
Lukas Burgey's avatar
Lukas Burgey committed
72
73
74
75
76
77
78
79
80
81
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
Lukas Burgey's avatar
Lukas Burgey committed
82
	var fetchedConfig fetchedConfig
83
	err = json.Unmarshal(body, &fetchedConfig)
Lukas Burgey's avatar
Lukas Burgey committed
84
	if err != nil {
85
		log.Fatalf("Unable to parse: %s %s", err, body)
Lukas Burgey's avatar
Lukas Burgey committed
86
87
		return
	}
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

	c.ExchangeName = fetchedConfig.RabbitMQConfig.ExchangeName
	c.Vhost = fetchedConfig.RabbitMQConfig.Vhost

	permittedServices := fetchedConfig.Services
	log.Printf("[Conf] Permitted services: %s", permittedServices)

	if len(c.Services) == 0 {
		log.Printf("[Conf] Config specifies no services. Using all permitted services")
	} else {
		// if the config specifies services we check if they are all permitted
		c.Services = filterPermitted(permittedServices, c.Services)
	}
	log.Printf("[Conf] Services: %s", c.Services)

Lukas Burgey's avatar
Lukas Burgey committed
103
104
105
	return
}

Lukas Burgey's avatar
Lukas Burgey committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
func filterPermitted(permitted []service, wanted map[string]service) (remainder map[string]service) {
	remainder = make(map[string]service, len(wanted))
serviceLoop:
	for _, service := range wanted {
		for _, permittedService := range permitted {
			if service.Name == permittedService.Name {
				remainder[service.Name] = service
				continue serviceLoop
			}
		}
		log.Printf("[Conn] Skipping unpermitted service %s", service)
	}
	return
}

121
func getConfig(configFile string) (c config, err error) {
122
123
124

	log.Printf("[Conf] Reading config file %s", configFile)

Lukas Burgey's avatar
Lukas Burgey committed
125
	bs, err := ioutil.ReadFile(configFile)
126
127
128
129
130
	if err != nil {
		log.Printf("[Conf] Error reading config file: %s", err)
		return
	}

Lukas Burgey's avatar
Lukas Burgey committed
131
132
	err = json.Unmarshal(bs, &c)
	if err != nil {
133
134
135
		log.Printf("[Conf] Error parsing config file: %s", err)
		return
	}
Lukas Burgey's avatar
Lukas Burgey committed
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	// check the config values
	if c.Host == "" {
		log.Fatalf("[Conf] No 'host' in config")
	}
	if c.Username == "" {
		log.Fatalf("[Conf] No 'user' in config")
	}
	if c.Password == "" {
		log.Fatalf("[Conf] No 'password' in config")
	}
	if c.FetchIntervalString == "" {
		log.Fatalf("[Conf] No 'fetch_interval' in config")
	}
	if c.ReconnectTimeoutString == "" {
		log.Fatalf("[Conf] No 'reconnect_timeout' in config")
Lukas Burgey's avatar
Lukas Burgey committed
152
	}
153
154

	// parse som of the config values
155
156
157
158
159
160
161
162
	if c.FetchInterval, err = time.ParseDuration(c.FetchIntervalString); err != nil {
		log.Printf("[Conf] Error parsing fetch interval: %s", err)
		return
	}
	if c.ReconnectTimeout, err = time.ParseDuration(c.ReconnectTimeoutString); err != nil {
		log.Printf("[Conf] Error parsing reconnect timeout: %s", err)
		return
	}
163
164
165
166
167
168
169

	// fetch the remote configuration
	err = c.fetchConfig()
	if err != nil {
		log.Fatalf("[Conf] Error fetching remote config: %s", err)
		return
	}
Lukas Burgey's avatar
Lukas Burgey committed
170

Lukas Burgey's avatar
Lukas Burgey committed
171
172
173
174
	// initialize the task queues
	c.NewTasks = make(chan task)
	c.DoneTasks = make(chan task)

Lukas Burgey's avatar
Lukas Burgey committed
175
176
	return
}
Lukas Burgey's avatar
Lukas Burgey committed
177
178

func main() {
Lukas Burgey's avatar
Lukas Burgey committed
179
	var err error
Lukas Burgey's avatar
Lukas Burgey committed
180
	app := kingpin.New("FEUDAL Client", "Client for the Federated User Credential Deployment Portal (FEUDAL)")
Lukas Burgey's avatar
Lukas Burgey committed
181

Lukas Burgey's avatar
Lukas Burgey committed
182
	configFile := app.Arg("config", "Config file to file to use.").Required().String()
Lukas Burgey's avatar
Lukas Burgey committed
183
	// oneshot := app.Flag("oneshot", "Fetch deployments with HTTP. Do not use rabbitmq.").Short('1').Bool()
Lukas Burgey's avatar
Lukas Burgey committed
184
185
186
187

	app.Author("Lukas Burgey")
	app.Version(version)

Lukas Burgey's avatar
Lukas Burgey committed
188
	// get arguments
Lukas Burgey's avatar
Lukas Burgey committed
189
190
	kingpin.MustParse(app.Parse(os.Args[1:]))

Lukas Burgey's avatar
Lukas Burgey committed
191
	// read the config file
192
	c, err := getConfig(*configFile)
193
194
195
196
	if err != nil {
		log.Fatalf("[Err] No valid config. Exiting")
	}

Lukas Burgey's avatar
Lukas Burgey committed
197
	if len(c.Services) < 1 {
Lukas Burgey's avatar
Lukas Burgey committed
198
199
		log.Printf("[P] Not starting pubsub because the are no services to subscribe to")
		return
Lukas Burgey's avatar
Lukas Burgey committed
200
201
	}

Lukas Burgey's avatar
Lukas Burgey committed
202
	// start task handler and acker
203
	go c.taskHandler()
Lukas Burgey's avatar
Lukas Burgey committed
204
	go c.taskAcker()
205

Lukas Burgey's avatar
Lukas Burgey committed
206
	consumer := c.consumer()
Lukas Burgey's avatar
Lukas Burgey committed
207
208
209
	defer func() {
		consumer.close()
	}()
Lukas Burgey's avatar
Lukas Burgey committed
210

Lukas Burgey's avatar
Lukas Burgey committed
211
	consumer.startConsuming()
Lukas Burgey's avatar
Lukas Burgey committed
212

Lukas Burgey's avatar
Lukas Burgey committed
213
214
215
	// start the fetcher after the consuming starts
	// -> we miss nothing
	go c.taskFetcher()
Lukas Burgey's avatar
Lukas Burgey committed
216

Lukas Burgey's avatar
Lukas Burgey committed
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
	// run till killed
	forever := make(chan bool)
	<-forever
	//if !*oneshot {
	//} else {
	//	// fetch once and exit
	//	if err := c.fetchTasks(); err != nil {
	//		log.Printf("[Fetch] error fetching: %s", err)
	//	}
	//	close(c.NewTasks)
	//	log.Printf("[Fetch] error fetching")
	//	c.taskHandler()

	//	close(c.DoneTasks)
	//	go c.taskAcker()
	//}
Lukas Burgey's avatar
Lukas Burgey committed
233
}