github.com/google/cloudprober@v0.11.3/cmd/cloudprober.go (about) 1 // Copyright 2017 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 /* 16 Binary cloudprober is a tool for running a set of probes and metric surfacers 17 on a GCE VM. Cloudprober takes in a config proto which dictates what probes 18 and surfacers should be created with what configuration, and then manages the 19 asynchronous fan-in/fan-out of the data between the probes and the surfacers. 20 */ 21 package main 22 23 import ( 24 "context" 25 "fmt" 26 _ "net/http/pprof" 27 "os" 28 "os/signal" 29 "runtime/pprof" 30 "syscall" 31 "time" 32 33 "cloud.google.com/go/compute/metadata" 34 "flag" 35 "github.com/golang/glog" 36 "github.com/google/cloudprober" 37 "github.com/google/cloudprober/common/file" 38 "github.com/google/cloudprober/config" 39 "github.com/google/cloudprober/config/runconfig" 40 "github.com/google/cloudprober/sysvars" 41 "github.com/google/cloudprober/web" 42 ) 43 44 var ( 45 configFile = flag.String("config_file", "", "Config file") 46 versionFlag = flag.Bool("version", false, "Print version and exit") 47 stopTime = flag.Duration("stop_time", 0, "How long to wait for cleanup before process exits on SIGINT and SIGTERM") 48 cpuprofile = flag.String("cpuprof", "", "Write cpu profile to file") 49 memprofile = flag.String("memprof", "", "Write heap profile to file") 50 configTest = flag.Bool("configtest", false, "Dry run to test config file") 51 dumpConfig = flag.Bool("dumpconfig", false, "Dump processed config to stdout") 52 testInstanceName = flag.String("test_instance_name", "ig-us-central1-a-01-0000", "Instance name example to be used in tests") 53 54 // configTestVars provides a sane set of sysvars for config testing. 55 configTestVars = map[string]string(nil) 56 ) 57 58 // This gets overwritten by using -ldflags="-X main.version=${VERSION}" at 59 // the build time. 60 var version = "undefined" 61 62 func setupConfigTestVars() { 63 configTestVars = map[string]string{ 64 "zone": "us-central1-a", 65 "project": "fake-domain.com:fake-project", 66 "project_id": "12345678", 67 "instance": *testInstanceName, 68 "internal_ip": "192.168.0.10", 69 "external_ip": "10.10.10.10", 70 "instance_template": "ig-us-central1-a-01", 71 "machine_type": "e2-small", 72 } 73 } 74 75 const ( 76 configMetadataKeyName = "cloudprober_config" 77 defaultConfigFile = "/etc/cloudprober.cfg" 78 ) 79 80 func setupProfiling() { 81 sigChan := make(chan os.Signal, 1) 82 signal.Notify(sigChan, os.Interrupt) 83 var f *os.File 84 if *cpuprofile != "" { 85 var err error 86 f, err = os.Create(*cpuprofile) 87 if err != nil { 88 glog.Exit(err) 89 } 90 if err = pprof.StartCPUProfile(f); err != nil { 91 glog.Errorf("Could not start CPU profiling: %v", err) 92 } 93 } 94 go func(file *os.File) { 95 <-sigChan 96 pprof.StopCPUProfile() 97 if *cpuprofile != "" { 98 if err := file.Close(); err != nil { 99 glog.Exit(err) 100 } 101 } 102 if *memprofile != "" { 103 f, err := os.Create(*memprofile) 104 if err != nil { 105 glog.Exit(err) 106 } 107 if err = pprof.WriteHeapProfile(f); err != nil { 108 glog.Exit(err) 109 } 110 if err := f.Close(); err != nil { 111 glog.Exit(err) 112 } 113 } 114 os.Exit(1) 115 }(f) 116 } 117 118 func configFileToString(fileName string) string { 119 b, err := file.ReadFile(fileName) 120 if err != nil { 121 glog.Exitf("Failed to read the config file: %v", err) 122 } 123 return string(b) 124 } 125 126 func getConfig() string { 127 if *configFile != "" { 128 return configFileToString(*configFile) 129 } 130 // On GCE first check if there is a config in custom metadata 131 // attributes. 132 if metadata.OnGCE() { 133 if config, err := config.ReadFromGCEMetadata(configMetadataKeyName); err != nil { 134 glog.Infof("Error reading config from metadata. Err: %v", err) 135 } else { 136 return config 137 } 138 } 139 // If config not found in metadata, check default config on disk 140 if _, err := os.Stat(defaultConfigFile); !os.IsNotExist(err) { 141 return configFileToString(defaultConfigFile) 142 } 143 glog.Warningf("Config file %s not found. Using default config.", defaultConfigFile) 144 return config.DefaultConfig() 145 } 146 147 func main() { 148 flag.Parse() 149 150 runconfig.SetVersion(version) 151 152 if *versionFlag { 153 fmt.Println(version) 154 return 155 } 156 157 setupConfigTestVars() 158 159 if *dumpConfig { 160 sysvars.Init(nil, configTestVars) 161 text, err := config.ParseTemplate(getConfig(), sysvars.Vars()) 162 if err != nil { 163 glog.Exitf("Error parsing config file. Err: %v", err) 164 } 165 fmt.Println(text) 166 return 167 } 168 169 if *configTest { 170 sysvars.Init(nil, configTestVars) 171 _, err := config.ParseForTest(configFileToString(*configFile), sysvars.Vars()) 172 if err != nil { 173 glog.Exitf("Error parsing config file. Err: %v", err) 174 } 175 return 176 } 177 178 setupProfiling() 179 180 err := cloudprober.InitFromConfig(getConfig()) 181 if err != nil { 182 glog.Exitf("Error initializing cloudprober. Err: %v", err) 183 } 184 185 // web.Init sets up web UI for cloudprober. 186 web.Init() 187 startCtx := context.Background() 188 189 if *stopTime == 0 { 190 *stopTime = time.Duration(cloudprober.GetConfig().GetStopTimeSec()) * time.Second 191 } 192 193 if *stopTime != 0 { 194 // Set up signal handling for the cancelation of the start context. 195 sigs := make(chan os.Signal, 1) 196 signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 197 ctx, cancelF := context.WithCancel(startCtx) 198 startCtx = ctx 199 200 go func() { 201 sig := <-sigs 202 glog.Warningf("Received signal \"%v\", canceling the start context and waiting for %v before closing", sig, *stopTime) 203 cancelF() 204 time.Sleep(*stopTime) 205 os.Exit(0) 206 }() 207 } 208 cloudprober.Start(startCtx) 209 210 // Wait forever 211 select {} 212 }