main.go 6.62 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
2
3
package main

import (
4
	"fmt"
Lukas Burgey's avatar
Lukas Burgey committed
5
6
7
	"io/ioutil"
	"log"
	"net/http"
Lukas Burgey's avatar
Lukas Burgey committed
8
	"os"
9
10
	"path"
	"path/filepath"
Lukas Burgey's avatar
Lukas Burgey committed
11

Lukas Burgey's avatar
Lukas Burgey committed
12
	"git.scc.kit.edu/feudal/feudalClient/config"
Lukas Burgey's avatar
Lukas Burgey committed
13
	deps "git.scc.kit.edu/feudal/feudalClient/deployments"
Lukas Burgey's avatar
Lukas Burgey committed
14
15
16
17
18
	"git.scc.kit.edu/feudal/feudalClient/sink"
	"git.scc.kit.edu/feudal/feudalClient/sink/script"
	"git.scc.kit.edu/feudal/feudalClient/source"
	"git.scc.kit.edu/feudal/feudalClient/source/amqp"
	"git.scc.kit.edu/feudal/feudalClient/source/rest"
Lukas Burgey's avatar
Lukas Burgey committed
19
	kingpin "gopkg.in/alecthomas/kingpin.v2"
Lukas Burgey's avatar
Lukas Burgey committed
20
21
22
)

var (
Lukas Burgey's avatar
Lukas Burgey committed
23
	app = kingpin.New(
Lukas Burgey's avatar
Lukas Burgey committed
24
25
26
27
		"FEUDAL Client",
		"Client for the Federated User Credential Deployment Portal (FEUDAL)",
	).Author(
		"Lukas Burgey",
Lukas Burgey's avatar
Lukas Burgey committed
28
	).Version(
29
		"v2.2.0",
Lukas Burgey's avatar
Lukas Burgey committed
30
	)
Lukas Burgey's avatar
Lukas Burgey committed
31
32
33
34
35
36
	cmdStart         = app.Command("start", "Starts the client in its normal operation mode.").Default()
	cmdDeregister    = app.Command("deregister", "Before disabling the client: Use deregister to inform the backend that the client ceases operation.")
	cmdSchema        = app.Command("schema", "Can be used to generate a JSON schema (Draft 4, see json-schema.org) for the validation of script inputs, outputs and the config of this client.")
	printSelector    = cmdSchema.Arg("selector", "Select the schema to generate. Options: input, output, config").Required().Enum("input", "output", "config")
	cmdValidate      = app.Command("validate", "Validate a input/output/config json. The json needs to be passed via stdin.")
	validateSelector = cmdValidate.Arg("selector", "Select the schema to validate against. Options: input, output, config").Required().Enum("input", "output", "config")
Lukas Burgey's avatar
Lukas Burgey committed
37

Lukas Burgey's avatar
Lukas Burgey committed
38
	configFile          = app.Flag("config", "Config file to use.").Short('c').String()
Lukas Burgey's avatar
Lukas Burgey committed
39
40
41
42
	scriptDebugging     = app.Flag("debug-scripts", "Display debugging info concerning executed scripts").Bool()
	backendDebugging    = app.Flag("debug-backend", "Display debugging info concerning the backend").Bool()
	debugAll            = app.Flag("debug", "Display all debugging info").Bool()
	sequentialExecution = app.Flag("seq", "Execute tasks sequentially").Bool()
Lukas Burgey's avatar
Lukas Burgey committed
43
44
)

Lukas Burgey's avatar
Lukas Burgey committed
45
func deregister(conf *config.Config) {
Lukas Burgey's avatar
Lukas Burgey committed
46
47
48
49
50
51
	var (
		err  error
		req  *http.Request
		resp *http.Response
	)
	log.Printf("Deregistering this client at the backend")
Lukas Burgey's avatar
Lukas Burgey committed
52

Lukas Burgey's avatar
Lukas Burgey committed
53
54
	req, err = http.NewRequest(
		"PUT",
Lukas Burgey's avatar
Lukas Burgey committed
55
		"https://"+conf.Hostname+"/backend/clientapi/deregister",
Lukas Burgey's avatar
Lukas Burgey committed
56
57
58
59
		nil,
	)
	if err != nil {
		log.Fatalf("Unable to deregister: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
60
	}
Lukas Burgey's avatar
Lukas Burgey committed
61
	req.SetBasicAuth(conf.Username, conf.Password)
Lukas Burgey's avatar
Lukas Burgey committed
62

Lukas Burgey's avatar
Lukas Burgey committed
63
	resp, err = (&http.Client{}).Do(req)
64
	if err != nil {
Lukas Burgey's avatar
Lukas Burgey committed
65
		log.Fatalf("Unable to deregister: %s", err)
66
	}
Lukas Burgey's avatar
Lukas Burgey committed
67
68
69
70
71
72
73
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Cannot read response body")
	}
	log.Printf("Response: %s", body)
}
74

Lukas Burgey's avatar
Lukas Burgey committed
75
76
func start(conf *config.Config) {
	if len(conf.EntitlementToServiceIDs) == 0 && len(conf.GroupToServiceIDs) == 0 {
Lukas Burgey's avatar
Lukas Burgey committed
77
78
		log.Printf("[P] Not starting pubsub because the are no services to subscribe to")
		return
Lukas Burgey's avatar
Lukas Burgey committed
79
80
	}

Lukas Burgey's avatar
Lukas Burgey committed
81
82
83
	// wire the pipes from sources to sink(s)
	sources := []source.Source{new(rest.Source), new(amqp.Source)}
	srcPipes := make([]<-chan deps.Dep, len(sources))
84

Lukas Burgey's avatar
Lukas Burgey committed
85
86
	sinks := []sink.Sink{new(script.Sink)}
	sinkPipe := make(chan deps.Dep)
Lukas Burgey's avatar
Lukas Burgey committed
87

Lukas Burgey's avatar
Lukas Burgey committed
88
	var err error
Lukas Burgey's avatar
Lukas Burgey committed
89
90
91
92
93
94
95
96
97
98
99
100
101
	for _, sink := range sinks {
		sink.Init(conf)
		err = sink.Connect((<-chan deps.Dep)(sinkPipe))
		if err != nil {
			log.Printf("Error connecting sink: %s", err)
		}
	}
	for i, src := range sources {
		src.Init(conf)
		srcPipes[i], err = src.Connect()
		if err != nil {
			log.Printf("Error connecting source: %s", err)
		}
Lukas Burgey's avatar
Lukas Burgey committed
102
	}
Lukas Burgey's avatar
Lukas Burgey committed
103

Lukas Burgey's avatar
Lukas Burgey committed
104
105
106
107
108
109
110
111
112
113
	// TODO rework
	var received deps.Dep
	for {
		select {
		case received = <-srcPipes[0]:
			sinkPipe <- received
		case received = <-srcPipes[1]:
			sinkPipe <- received
		}
	}
Lukas Burgey's avatar
Lukas Burgey committed
114
}
Lukas Burgey's avatar
Lukas Burgey committed
115

Lukas Burgey's avatar
Lukas Burgey committed
116
func prepareDebugging(conf *config.Config) {
Lukas Burgey's avatar
Lukas Burgey committed
117
118

	// Override the debug configuration with parameters
Lukas Burgey's avatar
Lukas Burgey committed
119
	if *debugAll {
120
121
		conf.Debug.Backend = true
		conf.Debug.Scripts = true
Lukas Burgey's avatar
Lukas Burgey committed
122
123
	}
	if *scriptDebugging {
Lukas Burgey's avatar
Lukas Burgey committed
124
		conf.Debug.Scripts = true
Lukas Burgey's avatar
Lukas Burgey committed
125
126
	}
	if *backendDebugging {
Lukas Burgey's avatar
Lukas Burgey committed
127
		conf.Debug.Backend = true
Lukas Burgey's avatar
Lukas Burgey committed
128
129
	}
	if *sequentialExecution {
Lukas Burgey's avatar
Lukas Burgey committed
130
		conf.Debug.Sequential = true
Lukas Burgey's avatar
Lukas Burgey committed
131
132
	}

Lukas Burgey's avatar
Lukas Burgey committed
133
134
135
136
137
138
139
140
	if conf.Debug.Scripts {
		log.Printf("[Debug] script debugging enabled")
	}
	if conf.Debug.Backend {
		log.Printf("[Debug] backend debugging enabled")
	}
	if conf.Debug.Sequential {
		log.Printf("[Debug] Executing tasks sequentially")
Lukas Burgey's avatar
Lukas Burgey committed
141
	}
Lukas Burgey's avatar
Lukas Burgey committed
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// search for a config file
// dir pattern: $HOME/.config -> /etc/feudal -> $CWD
// file pattern: *.yaml -> *.json
func findConfigFile(arg string) (handle *os.File, err error) {
	globString := func(gs string) string {
		var files []string
		files, err = filepath.Glob(gs)
		if err == nil && len(files) > 0 {
			log.Printf("Globbed: %v", files)
			_, err = os.Stat(files[0])
			if err == nil {
				return files[0]
			} else {
				log.Printf("Error opening: %s", err)
			}
		}
		return ""
	}
	globDir := func(ds string) (name string) {
		name = globString(path.Join(ds, "*.yaml"))
		if name != "" {
			return
		}
		name = globString(path.Join(ds, "*.json"))
		if name != "" {
			return
		}
		return
	}
	findName := func() string {
		name := ""
		if *configFile != "" {
			// check if file exists
			_, err = os.Stat(*configFile)
			if err == nil {
				return *configFile
			} else {
				log.Printf("Error opening: %s", err)
			}
		}

		var home, cwd string

		// search $HOME/.config
		if home, err = os.UserHomeDir(); err == nil {
			name = globDir(path.Join(home, ".config/feudal"))
			if name != "" {
				return name
			}
		}
		name = globDir("/etc/feudal")
		if name != "" {
			return name
		}

		cwd, err = os.Getwd()
		if err == nil {
			name = globDir(cwd)
			if name != "" {
				return name
			}
		}
		return ""
	}

	firstName := findName()

	if firstName == "" {
		err = fmt.Errorf(`No config file!
Provide -c/--config or place a config json/yaml in $HOME/.config/feudal or /etc/feudal or the current working directory`)
		return
	}

	return os.Open(firstName)
}

Lukas Burgey's avatar
Lukas Burgey committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
func main() {
	var err error

	// get arguments
	cmd := kingpin.MustParse(app.Parse(os.Args[1:]))

	// Execute commands that don't need the config
	switch cmd {
	case "schema":
		printSchema(*printSelector)
		return
	case "validate":
		result, err := validateJSON(*validateSelector, os.Stdin)
		if err != nil {
			log.Fatal(err)
		}
		printValidationResult(result)
		return
	}

240
241
	// search appropriate config
	handle, err := findConfigFile(*configFile)
242
243
244
	if err != nil {
		log.Fatalf("[Conf] Error opening config file: %s", err)
	}
245
	log.Printf("[Conf] Opened config file %s", handle.Name())
246

247
248
	// read the config file
	conf, err := config.ReadConfig(handle, handle.Name())
Lukas Burgey's avatar
Lukas Burgey committed
249
250
251
252
253
	if err != nil {
		log.Fatalf("[Conf] %s", err)
	}

	prepareDebugging(conf)
Lukas Burgey's avatar
Lukas Burgey committed
254
255
256

	switch cmd {
	case "start":
Lukas Burgey's avatar
Lukas Burgey committed
257
		// sync the config with the backend
Lukas Burgey's avatar
Lukas Burgey committed
258
		if err := conf.Sync(); err != nil {
Lukas Burgey's avatar
Lukas Burgey committed
259
			log.Printf("[Conf] Error synchronizing configuration: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
260
261
			return
		}
Lukas Burgey's avatar
Lukas Burgey committed
262
		start(conf)
Lukas Burgey's avatar
Lukas Burgey committed
263
264

	case "deregister":
Lukas Burgey's avatar
Lukas Burgey committed
265
		deregister(conf)
Lukas Burgey's avatar
Lukas Burgey committed
266
267
	}
}