Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/service-waiter/cmd/root.go
2498 views
1
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package cmd
6
7
import (
8
"fmt"
9
"os"
10
"time"
11
12
homedir "github.com/mitchellh/go-homedir"
13
"github.com/spf13/cobra"
14
"github.com/spf13/viper"
15
16
"github.com/gitpod-io/gitpod/common-go/log"
17
)
18
19
var (
20
// ServiceName is the name we use for tracing/logging
21
ServiceName = "service-waiter"
22
// Version of this service - set during build
23
Version = ""
24
)
25
26
var cfgFile string
27
var jsonLog bool
28
var verbose bool
29
30
// rootCmd represents the base command when called without any subcommands
31
var rootCmd = &cobra.Command{
32
Use: "service-waiter",
33
Short: "service-waiter waits until a service becomes available",
34
PersistentPreRun: func(cmd *cobra.Command, args []string) {
35
log.Init(ServiceName, Version, jsonLog, verbose)
36
},
37
}
38
39
// Execute adds all child commands to the root command and sets flags appropriately.
40
// This is called by main.main(). It only needs to happen once to the rootCmd.
41
func Execute() {
42
if err := rootCmd.Execute(); err != nil {
43
fmt.Println(err)
44
os.Exit(1)
45
}
46
}
47
48
func init() {
49
cobra.OnInitialize(initConfig)
50
51
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.service-waiter.yaml)")
52
rootCmd.PersistentFlags().BoolVarP(&jsonLog, "json-log", "j", true, "produce JSON log output on verbose level")
53
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose JSON logging")
54
55
defaultTimeout := os.Getenv("SERVICE_WAITER_TIMEOUT")
56
if defaultTimeout == "" {
57
defaultTimeout = "5m"
58
}
59
rootCmd.PersistentFlags().StringP("timeout", "t", defaultTimeout, "the maximum time to wait for")
60
61
err := viper.BindPFlags(rootCmd.PersistentFlags())
62
if err != nil {
63
log.WithError(err).Fatal("cannot bind Viper to pflags")
64
}
65
}
66
67
// initConfig reads in config file and ENV variables if set.
68
func initConfig() {
69
if cfgFile != "" {
70
// Use config file from the flag.
71
viper.SetConfigFile(cfgFile)
72
} else {
73
// Find home directory.
74
home, err := homedir.Dir()
75
if err != nil {
76
fmt.Println(err)
77
os.Exit(1)
78
}
79
80
// Search config in home directory with name ".service-waiter" (without extension).
81
viper.AddConfigPath(home)
82
viper.SetConfigName(".service-waiter")
83
}
84
85
viper.AutomaticEnv() // read in environment variables that match
86
87
// If a config file is found, read it in.
88
if err := viper.ReadInConfig(); err == nil {
89
fmt.Println("Using config file:", viper.ConfigFileUsed())
90
}
91
}
92
93
func getTimeout() time.Duration {
94
t := viper.GetString("timeout")
95
timeout, err := time.ParseDuration(t)
96
if err != nil {
97
log.WithError(err).Fatal("cannot parse timeout")
98
}
99
100
return timeout
101
}
102
103
// fail ends the waiting process propagating the message on its way out
104
func fail(message string) {
105
terminationLog := "/dev/termination-log"
106
107
log.WithField("message", message).Warn("failed to wait for a service")
108
109
if _, err := os.Stat(terminationLog); !os.IsNotExist(err) {
110
err := os.WriteFile(terminationLog, []byte(message), 0600)
111
if err != nil {
112
log.WithError(err).Error("cannot write termination log")
113
}
114
}
115
116
os.Exit(1)
117
}
118
119
func envOrDefault(env, def string) (res string) {
120
res = os.Getenv(env)
121
if res == "" {
122
res = def
123
}
124
125
return
126
}
127
128