rest.go 2.62 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
2
3
4
5
6
7
8
9
10
11
package rest

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"git.scc.kit.edu/feudal/feudalClient/config"
12
	deps "git.scc.kit.edu/feudal/feudalClient/deployments"
lukasburgey's avatar
lukasburgey committed
13
	"git.scc.kit.edu/feudal/feudalClient/indent"
Lukas Burgey's avatar
Lukas Burgey committed
14
15
16
17
18
19
20
21
22
23
)

type (
	// Source implements the DepSource interface for http
	Source struct {
		Config *config.Config
		Ticker *time.Ticker
	}
)

24
25
26
27
var (
	httpClient = &http.Client{}
)

Lukas Burgey's avatar
Lukas Burgey committed
28
29
30
31
32
33
34
35
36
37
func (src Source) fetchDeps(sink chan<- deps.Dep) (err error) {
	if len(src.Config.EntitlementToServiceIDs) == 0 && len(src.Config.GroupToServiceIDs) == 0 {
		log.Printf("[HTTP] Not fetching because the are no services to fetch")
		return
	}
	if src.Config.Debug.Backend {
		log.Printf("[HTTP] Fetching")
	}

	// construct a request
38
	uri := "https://" + src.Config.Hostname + "/client/dep-states"
Lukas Burgey's avatar
Lukas Burgey committed
39
40
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
41
		err = fmt.Errorf("Request creation failed: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
42
43
44
45
46
		return
	}
	req.SetBasicAuth(src.Config.Username, src.Config.Password)

	// execute the request
47
	resp, err := httpClient.Do(req)
Lukas Burgey's avatar
Lukas Burgey committed
48
	if err != nil {
49
		err = fmt.Errorf("Request failed: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
50
51
52
53
		return
	}
	defer resp.Body.Close()

54
55
56
57
58
59
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		err = fmt.Errorf("Reading response body: %s", err)
		return
	}

Lukas Burgey's avatar
Lukas Burgey committed
60
	if resp.StatusCode != 200 {
61
		err = fmt.Errorf("Unable to fetch tasks (response: %v, body: %s)", resp.Status, body)
Lukas Burgey's avatar
Lukas Burgey committed
62
63
64
65
66
67
		return
	}

	var newDeps []deps.Dep
	err = json.Unmarshal(body, &newDeps)
	if err != nil {
68
		err = fmt.Errorf("Unmarshaling response body: %s\n%s", err, body)
Lukas Burgey's avatar
Lukas Burgey committed
69
70
71
72
		return
	}

	if src.Config.Debug.Backend {
lukasburgey's avatar
lukasburgey committed
73
		log.Printf("[HTTP] Fetched: %s", indent.Indent(body))
Lukas Burgey's avatar
Lukas Burgey committed
74
75
	}

76
77
78
79
80
	go func() {
		for _, newDep := range newDeps {
			sink <- newDep
		}
	}()
Lukas Burgey's avatar
Lukas Burgey committed
81
82
83
84
85
86
87
88
89
	return
}

// Init initializes the http source
func (src *Source) Init(conf *config.Config) {
	src.Config = conf
}

// Connect starts fetching using the rest interface.
90
func (src *Source) Connect() (<-chan deps.Dep, error) {
Lukas Burgey's avatar
Lukas Burgey committed
91
	sinkPipe := make(chan deps.Dep)
92
	sink := sinkPipe
Lukas Burgey's avatar
Lukas Burgey committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

	// start ticker
	src.Ticker = time.NewTicker(src.Config.FetchInterval)

	// fetch when the ticker ticks
	go func() {
		var err error
		for {
			select {
			case _, ok := <-src.Ticker.C:
				if !ok {
					log.Printf("[HTTP] Source stopping")
					return
				}
				err = src.fetchDeps(sinkPipe)
				if err != nil {
109
					log.Printf("[HTTP] Error fetching: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
110
111
112
113
114
115
116
				}
			}
		}
	}()

	// start one fetch right now
	go func() {
117
118
119
		err := src.fetchDeps(sinkPipe)
		if err != nil {
			log.Printf("[HTTP] Error fetching: %s", err)
Lukas Burgey's avatar
Lukas Burgey committed
120
121
122
123
		}
	}()

	log.Printf("[HTTP] Source connected")
124
	return sink, nil
Lukas Burgey's avatar
Lukas Burgey committed
125
126
127
128
129
130
}

// Close stop the fetching
func (src *Source) Close() {
	src.Ticker.Stop()
}