forked from kiali/kiali
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkiali.go
173 lines (145 loc) · 4.75 KB
/
kiali.go
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
// Kiali
//
// Kiali project, observability for the Istio service mesh
//
// Schemes: http, https
// BasePath: /api
// Version: _
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"os/signal"
"regexp"
"strings"
"github.com/golang/glog"
"github.com/kiali/kiali/config"
"github.com/kiali/kiali/log"
"github.com/kiali/kiali/prometheus/internalmetrics"
"github.com/kiali/kiali/server"
"github.com/kiali/kiali/status"
"github.com/kiali/kiali/util"
)
// Identifies the build. These are set via ldflags during the build (see Makefile).
var (
version = "unknown"
commitHash = "unknown"
)
// Command line arguments
var (
argConfigFile = flag.String("config", "", "Path to the YAML configuration file. If not specified, environment variables will be used for configuration.")
)
func init() {
// log everything to stderr so that it can be easily gathered by logs, separate log files are problematic with containers
flag.Set("logtostderr", "true")
}
func main() {
defer glog.Flush()
util.Clock = util.RealClock{}
// process command line
flag.Parse()
validateFlags()
// log startup information
log.Infof("Kiali: Version: %v, Commit: %v\n", version, commitHash)
log.Debugf("Kiali: Command line: [%v]", strings.Join(os.Args, " "))
// load config file if specified, otherwise, rely on environment variables to configure us
if *argConfigFile != "" {
c, err := config.LoadFromFile(*argConfigFile)
if err != nil {
glog.Fatal(err)
}
config.Set(c)
} else {
log.Infof("No configuration file specified. Will rely on environment for configuration.")
config.Set(config.NewConfig())
}
log.Tracef("Kiali Configuration:\n%s", config.Get())
if err := validateConfig(); err != nil {
glog.Fatal(err)
}
consoleVersion := determineConsoleVersion()
log.Infof("Kiali: Console version: %v", consoleVersion)
status.Put(status.ConsoleVersion, consoleVersion)
status.Put(status.CoreVersion, version)
status.Put(status.CoreCommitHash, commitHash)
if webRoot := config.Get().Server.WebRoot; webRoot != "/" {
util.UpdateBaseURL(webRoot)
util.ConfigToJS()
}
// prepare our internal metrics so Prometheus can scrape them
internalmetrics.RegisterInternalMetrics()
// Start listening to requests
server := server.NewServer()
server.Start()
// wait forever, or at least until we are told to exit
waitForTermination()
// Shutdown internal components
log.Info("Shutting down internal components")
server.Stop()
}
func waitForTermination() {
// Channel that is notified when we are done and should exit
// TODO: may want to make this a package variable - other things might want to tell us to exit
var doneChan = make(chan bool)
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
go func() {
for range signalChan {
log.Info("Termination Signal Received")
doneChan <- true
}
}()
<-doneChan
}
func validateConfig() error {
if config.Get().Server.Port < 0 {
return fmt.Errorf("server port is negative: %v", config.Get().Server.Port)
}
if err := config.Get().Server.Credentials.ValidateCredentials(); err != nil {
return fmt.Errorf("server credentials are invalid: %v", err)
}
if strings.Contains(config.Get().Server.StaticContentRootDirectory, "..") {
return fmt.Errorf("server static content root directory must not contain '..': %v", config.Get().Server.StaticContentRootDirectory)
}
if _, err := os.Stat(config.Get().Server.StaticContentRootDirectory); os.IsNotExist(err) {
return fmt.Errorf("server static content root directory does not exist: %v", config.Get().Server.StaticContentRootDirectory)
}
validPathRegEx := regexp.MustCompile(`^\/[a-zA-Z\d_\$]*$`)
if path := config.Get().Server.WebRoot; !validPathRegEx.MatchString(path) {
return fmt.Errorf("web root must begin with a / and contain only alphanumerics: %v", path)
}
return nil
}
func validateFlags() {
if *argConfigFile != "" {
if _, err := os.Stat(*argConfigFile); err != nil {
if os.IsNotExist(err) {
log.Debugf("Configuration file [%v] does not exist.", *argConfigFile)
}
}
}
}
// determineConsoleVersion will return the version of the UI console the server will serve to clients.
// Note this method requires the configuration to be loaded and available via config.Get()
func determineConsoleVersion() string {
consoleVersion := "unknown"
filename := config.Get().Server.StaticContentRootDirectory + "/version.txt"
fileContent, err := ioutil.ReadFile(filename)
if err == nil {
consoleVersion = string(fileContent)
consoleVersion = strings.TrimSpace(consoleVersion) // also seems to kill off EOF
} else {
log.Errorf("Failed to determine console version from file [%v]. error=%v", filename, err)
}
return consoleVersion
}