1
31 package cmdline
32
33 import (
34 "flag"
35 "fmt"
36 "io/ioutil"
37 "os"
38 "strings"
39 "sync"
40 "time"
41
42 pb "golang.conradwood.net/apis/goeasyops"
43 "golang.conradwood.net/go-easyops/appinfo"
44 "golang.conradwood.net/go-easyops/common"
45 "gopkg.in/yaml.v2"
46 )
47
48 const (
49 CONFIG_FILE = "/tmp/goeasyops.config"
50 REGISTRY_DEFAULT = "localhost:5000"
51 )
52
53 var (
54 debug_rpc_client = flag.Bool("ge_debug_rpc_client", false, "set to true to debug remote invokations")
55 debug_rpc_serve = flag.Bool("ge_debug_rpc_server", false, "debug the grpc server ")
56 default_timeout = flag.Duration("ge_ctx_deadline", time.Duration(10)*time.Second, "the default timeout for contexts. do not change in production")
57 reg_env = ENV("GE_REGISTRY", "default registry address")
58 e_ctx = ENV("GE_CTX", "a serialised context to use when creating new ones")
59 config *pb.Config
60
61 internal_flag_names = []string{"token", "registry", "registry_resolver", "AD_started_by_auto_deployer", "X"}
62 debug_auth = flag.Bool("ge_debug_auth", false, "debug auth stuff")
63 debug_sig = flag.Bool("ge_debug_signature", false, "debug signature stuff")
64 mlock sync.Mutex
65 running_in_datacenter = flag.Bool("AD_started_by_auto_deployer", false, "the autodeployer sets this to true to modify the behaviour to make it suitable for general-availability services in the datacenter")
66
67 registry = flag.String("registry", REGISTRY_DEFAULT, "address of the registry server. This is used for registration as well as resolving unless -registry_resolver is set, in which case this is only used for registration")
68 registry_resolver = flag.String("registry_resolver", "", "address of the registry server (for lookups)")
69 instance_id = flag.String("ge_instance_id", "", "autodeployers internal instance id. We may use this to get information about ourselves")
70 ext_help = flag.Bool("X", false, "extended help")
71 XXdoappinfo = ImmediatePara("ge_info", "print application build number", doappinfo)
72 print_easyops = false
73 manreg = ""
74 stdalone = flag.Bool("ge_standalone", false, "if true, do not use a registry, just run stuff standlone")
75
76 context_build_version = flag.Int("ge_context_builder_version", 2, "the version to create by the context builder (0=do not use context builder)")
77 overridden_env_context = ""
78 enabled_experiments = flag.String("ge_enable_experiments", "", "a comma delimited set of names of experiments to enable with this context")
79 debug_ctx = flag.Bool("ge_debug_context", false, "if true debug context stuff")
80 )
81
82
83
84
85
86 func init() {
87 flag.Usage = PrintUsage
88 for _, o := range os.Args {
89 if o == "-X" {
90 go print_late_usage()
91 }
92 }
93
94
95 err := readConfig(CONFIG_FILE)
96 if err != nil {
97 os.Exit(10)
98 }
99 }
100 func readConfig(filename string) error {
101 _, err := os.Stat(filename)
102 if err != nil {
103 return nil
104 }
105 b, err := ioutil.ReadFile(filename)
106 if err != nil {
107 fmt.Printf("[go-easyops] failed to read file %s: %s\n", filename, err)
108 return err
109 }
110 cfg := &pb.Config{}
111 err = yaml.UnmarshalStrict(b, cfg)
112 if err != nil {
113 fmt.Printf("[go-easyops] invalid file %s: %s\n", filename, err)
114 return err
115 }
116 config = cfg
117 return nil
118 }
119
120
121
122 func print_late_usage() {
123 fmt.Printf("[go-easyops] Printing extended help after flag.Parse() was called...\n")
124 st := time.Now()
125 for *ext_help == false {
126 if time.Since(st) > time.Duration(5)*time.Second {
127 break
128 }
129 }
130 print_easyops = true
131 PrintUsage()
132 os.Exit(0)
133 }
134
135 func PrintUsage() {
136 fmt.Fprintf(os.Stdout, "(C) Conrad Wood.\n")
137 fmt.Fprintf(os.Stdout, " Go-Easyops version : %d\n", BUILD_NUMBER)
138 fmt.Fprintf(os.Stdout, " Go-Easyops build timestamp : %d\n", BUILD_TIMESTAMP)
139 fmt.Fprintf(os.Stdout, " Go-Easyops build time : %s\n", time.Unix(BUILD_TIMESTAMP, 0))
140 fmt.Fprintf(os.Stdout, " Go-Easyops description : %s\n", BUILD_DESCRIPTION)
141
142 fmt.Fprintf(os.Stdout, " App version : %d\n", appinfo.AppInfo().Number)
143 fmt.Fprintf(os.Stdout, " App build timestamp : %d\n", appinfo.AppInfo().Timestamp)
144 fmt.Fprintf(os.Stdout, " App build time : %s\n", time.Unix(appinfo.AppInfo().Timestamp, 0))
145 fmt.Fprintf(os.Stdout, " App description : %s\n", appinfo.AppInfo().Description)
146 fmt.Fprintf(os.Stdout, " App artefactid : %d\n", appinfo.AppInfo().ArtefactID)
147 fmt.Fprintf(os.Stdout, " App repository : %d\n", appinfo.AppInfo().RepositoryID)
148 fmt.Fprintf(os.Stdout, " App repository git url : %s\n", appinfo.AppInfo().GitURL)
149 fmt.Fprintf(os.Stdout, " Source code path : %s\n", SourceCodePath())
150
151 PrintDefaults()
152 }
153 func PrintDefaults() {
154 if print_easyops {
155 fmt.Fprintf(os.Stdout, "\nGo-easyops Usage:\n")
156 } else {
157 fmt.Fprintf(os.Stdout, "\nUsage:\n")
158 }
159 f := flag.CommandLine
160 f.VisitAll(func(fg *flag.Flag) {
161 isext := strings.HasPrefix(fg.Name, "ge_")
162 if !isext {
163 for _, s := range internal_flag_names {
164 if fg.Name == s {
165 isext = true
166 break
167 }
168 }
169 }
170 if print_easyops != isext {
171 return
172 }
173 s := fmt.Sprintf(" -%s", fg.Name)
174 name, usage := flag.UnquoteUsage(fg)
175 if len(name) > 0 {
176 s += " " + name
177 }
178
179
180 if len(s) <= 4 {
181 s += "\t"
182 } else {
183
184
185 s += "\n \t"
186 }
187 s += strings.ReplaceAll(usage, "\n", "\n \t")
188
189 s += fmt.Sprintf(" (default %v)", fg.DefValue)
190
191 fmt.Printf("%s\n", s)
192 })
193 fmt.Printf(`
194 Yaml Mapping file: /etc/yacloud/config/service_map.yaml
195 Defaults override file: /tmp/goeasyops.config
196 Environment Variables:
197 `)
198
199 s := render_env_help()
200 fmt.Println(s)
201
202 }
203 func GetInstanceID() string {
204 s := *instance_id
205 if s == "" {
206 mlock.Lock()
207 defer mlock.Unlock()
208 if *instance_id != "" {
209 return *instance_id
210 }
211 s = "L-" + RandomString(32)
212 *instance_id = s
213 }
214 return s
215 }
216 func GetPid() uint64 {
217 p := os.Getpid()
218 return uint64(p)
219 }
220
221
222 func GetClientRegistryAddress() string {
223 if manreg != "" {
224 return manreg
225 }
226 if *registry_resolver == "" {
227 return GetRegistryAddress()
228 }
229 res := *registry_resolver
230 if !strings.Contains(res, ":") {
231 res = fmt.Sprintf("%s:5000", res)
232 }
233 return res
234 }
235
236
237 func SetClientRegistryAddress(reg string) {
238 if !strings.Contains(reg, ":") {
239 reg = fmt.Sprintf("%s:5000", reg)
240 }
241 manreg = reg
242 common.NotifyRegistryChangeListeners()
243 }
244
245
246 func GetRegistryAddress() string {
247 res := *registry
248 if *registry == REGISTRY_DEFAULT {
249 s := reg_env.Value()
250 if s != "" {
251 res = s
252 }
253 }
254 if *registry == REGISTRY_DEFAULT {
255 if config != nil && config.Registry != "" {
256 res = config.Registry
257 }
258 }
259 if !strings.Contains(res, ":") {
260 res = fmt.Sprintf("%s:5000", res)
261 }
262 return res
263 }
264
265 func Datacenter() bool {
266 return *running_in_datacenter
267 }
268
269
270 func SetDatacenter(b bool) {
271 *running_in_datacenter = b
272 }
273
274
275 func OptEnvString(para, envname string) string {
276 if para != "" {
277 return para
278 }
279 return os.Getenv(envname)
280 }
281 func doappinfo() {
282 fmt.Printf("%d\n", appinfo.AppInfo().Number)
283 os.Exit(0)
284 }
285 func IsStandalone() bool {
286 return *stdalone
287 }
288 func LocalRegistrationDir() string {
289 return "/tmp/local_registry"
290 }
291 func ContextWithBuilder() bool {
292 return true
293
294 }
295
296
297 func GetContextBuilderVersion() int {
298 version := *context_build_version
299 if version != 2 {
300 panic(fmt.Sprintf("Unsupported context version (%d)", version))
301 }
302 return version
303 }
304
305
306 func SetContextBuilderVersion(version int) {
307 if version != 2 {
308 panic(fmt.Sprintf("Unsupported context version (%d)", version))
309 }
310 *context_build_version = version
311 }
312
313
314 func GetEnvContext() string {
315 if overridden_env_context != "" {
316 s := overridden_env_context
317 if len(s) > 10 {
318 s = s[:10]
319 }
320 fmt.Printf("[go-easyops] using overriden env context (%s )\n", s)
321 return overridden_env_context
322 }
323 return e_ctx.Value()
324 }
325 func DebugSignature() bool {
326 return *debug_sig
327 }
328 func DebugAuth() bool {
329 return *debug_auth
330 }
331
332
333 func SetEnvContext(s string) {
334 overridden_env_context = s
335 }
336
337
338 func GetYACloudDir() string {
339 dirs := []string{
340 "/opt/yacloud/current",
341 "/opt/yacloud/",
342 }
343 for _, res := range dirs {
344 dname := res + "/ctools"
345 st, err := os.Stat(dname)
346 if err != nil {
347 continue
348 }
349 if st.IsDir() {
350 return res
351 }
352 }
353 return ""
354 }
355
356
357 func DefaultTimeout() time.Duration {
358 return *default_timeout
359 }
360
361 func EnabledExperiments() []string {
362 exs := *enabled_experiments
363 if len(exs) == 0 {
364 return nil
365 }
366 ex := strings.Split(exs, ",")
367 var res []string
368 for _, e := range ex {
369 e = strings.Trim(e, " ")
370 res = append(res, e)
371 }
372 return res
373 }
374
375
376 func DebugfContext(format string, args ...interface{}) {
377 if !*debug_ctx {
378 return
379 }
380 x := fmt.Sprintf(format, args...)
381 fmt.Printf("[go-easyops/debugctx] %s", x)
382 }
383
384
385 func DebugfRPC(format string, args ...interface{}) {
386 if !*debug_ctx {
387 return
388 }
389 x := fmt.Sprintf(format, args...)
390 fmt.Printf("[go-easyops/rpc] %s", x)
391 }
392
393 func SetDebugContext() {
394 *debug_ctx = true
395 }
396 func IsDebugRPCClient() bool {
397 return *debug_rpc_client
398 }
399 func IsDebugRPCServer() bool {
400 return *debug_rpc_serve
401 }
402
403
404 func IsEasyopsFlag(name string) bool {
405 if strings.HasPrefix(name, "ge_") {
406 return true
407 }
408 for _, ifn := range internal_flag_names {
409 if ifn == name {
410 return true
411 }
412 }
413 return false
414 }
415
View as plain text