github.com/RedHatInsights/insights-content-service@v1.0.0/content-service.go (about) 1 /* 2 Copyright © 2020, 2021 Red Hat, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Entry point to the insights content service 18 package main 19 20 import ( 21 "bytes" 22 "encoding/json" 23 "fmt" 24 "os" 25 "strings" 26 27 "github.com/RedHatInsights/insights-operator-utils/logger" 28 "github.com/RedHatInsights/insights-operator-utils/metrics" 29 "github.com/rs/zerolog/log" 30 31 "github.com/RedHatInsights/insights-content-service/conf" 32 "github.com/RedHatInsights/insights-content-service/content" 33 "github.com/RedHatInsights/insights-content-service/groups" 34 "github.com/RedHatInsights/insights-content-service/server" 35 ) 36 37 // ExitCode represents numeric value returned to parent process when the 38 // current process finishes 39 type ExitCode int 40 41 const ( 42 // ExitStatusOK means that the tool finished with success 43 ExitStatusOK = iota 44 45 // ExitStatusServerError is returned in case of any REST API server-related error 46 ExitStatusServerError 47 48 // ExitStatusReadContentError is returned when the static content parsing fails 49 ExitStatusReadContentError 50 51 // ExitStatusOther represents other errors that might happen 52 ExitStatusOther 53 54 defaultConfigFilename = "config" 55 ) 56 57 var ( 58 serverInstance *server.HTTPServer 59 60 // BuildVersion contains the major.minor version of the CLI client 61 BuildVersion = "*not set*" 62 63 // BuildTime contains timestamp when the CLI client has been built 64 BuildTime = "*not set*" 65 66 // BuildBranch contains Git branch used to build this application 67 BuildBranch = "*not set*" 68 69 // BuildCommit contains Git commit used to build this application 70 BuildCommit = "*not set*" 71 72 // UtilsVersion contains currently used version of 73 // github.com/RedHatInsights/insights-operator-utils package 74 UtilsVersion = "*not set*" 75 76 // OCPRulesVersion contains currently used version of 77 // https://gitlab.cee.redhat.com/ccx/ccx-rules-ocp package 78 OCPRulesVersion = "*not set*" 79 ) 80 81 // startService starts service and returns error code 82 func startService() ExitCode { 83 serverCfg := conf.GetServerConfiguration() 84 groupsCfg := conf.GetGroupsConfiguration() 85 86 parsedGroups, err := groups.ParseGroupConfigFile(groupsCfg.ConfigPath) 87 if err != nil { 88 log.Error().Err(err).Msg("Groups init error") 89 return ExitStatusServerError 90 } 91 92 metricsCfg := conf.GetMetricsConfiguration() 93 if metricsCfg.Namespace != "" { 94 metrics.AddAPIMetricsWithNamespace(metricsCfg.Namespace) 95 } 96 97 ruleContentDirPath := conf.GetContentPathConfiguration() 98 99 contentDir, ruleContentStatusMap, err := content.ParseRuleContentDir(ruleContentDirPath) 100 if osPathError, ok := err.(*os.PathError); ok { 101 log.Error().Err(osPathError).Msg("No rules directory") 102 return ExitStatusReadContentError 103 } else if err != nil { 104 log.Error().Err(err).Msg("error happened during parsing rules content dir") 105 return ExitStatusReadContentError 106 } 107 108 // start the HTTP server on specified port 109 serverInstance = server.New(serverCfg, parsedGroups, contentDir, 110 ruleContentStatusMap) 111 112 // fill-in additional info used by /info endpoint handler 113 fillInInfoParams(serverInstance.InfoParams) 114 115 err = serverInstance.Start() 116 if err != nil { 117 log.Error().Err(err).Msg("HTTP(s) start error") 118 return ExitStatusServerError 119 } 120 121 return ExitStatusOK 122 } 123 124 // fillInInfoParams function fills-in additional info used by /info endpoint 125 // handler 126 func fillInInfoParams(params map[string]string) { 127 params["BuildVersion"] = BuildVersion 128 params["BuildTime"] = BuildTime 129 params["BuildBranch"] = BuildBranch 130 params["BuildCommit"] = BuildCommit 131 params["UtilsVersion"] = UtilsVersion 132 params["OCPRulesVersion"] = OCPRulesVersion 133 } 134 135 func printInfo(msg, val string) { 136 fmt.Printf("%s\t%s\n", msg, val) 137 } 138 139 func printVersionInfo() ExitCode { 140 printInfo("Version:", BuildVersion) 141 printInfo("Build time:", BuildTime) 142 printInfo("Branch:", BuildBranch) 143 printInfo("Commit:", BuildCommit) 144 printInfo("Utils version:", UtilsVersion) 145 printInfo("OCP rules version:", OCPRulesVersion) 146 return ExitStatusOK 147 } 148 149 func printGroups() ExitCode { 150 groupsConfig := conf.GetGroupsConfiguration() 151 groupsMap, err := groups.ParseGroupConfigFile(groupsConfig.ConfigPath) 152 153 if err != nil { 154 log.Error().Err(err).Msg("Groups parsing error") 155 return ExitStatusServerError 156 } 157 158 fmt.Println(groupsMap) 159 return ExitStatusOK 160 } 161 162 func printRules() ExitCode { 163 log.Info().Msg("Printing rules") 164 contentPath := conf.GetContentPathConfiguration() 165 contentDir, _, err := content.ParseRuleContentDir(contentPath) 166 167 if err != nil { 168 log.Error().Err(err).Msg("Error parsing the content") 169 return ExitStatusReadContentError 170 } 171 172 buffer := new(bytes.Buffer) 173 encoder := json.NewEncoder(buffer) 174 175 if err := encoder.Encode(contentDir); err == nil { 176 fmt.Println(buffer) 177 return ExitStatusOK 178 } 179 180 return ExitStatusOther 181 182 } 183 184 func printParseStatus() ExitCode { 185 log.Info().Msg("Printing parse status") 186 contentPath := conf.GetContentPathConfiguration() 187 _, parseStatus, err := content.ParseRuleContentDir(contentPath) 188 189 if err != nil { 190 log.Error().Err(err).Msg("Error parsing the content") 191 return ExitStatusReadContentError 192 } 193 194 buffer := new(bytes.Buffer) 195 encoder := json.NewEncoder(buffer) 196 197 if err := encoder.Encode(parseStatus); err == nil { 198 fmt.Println(buffer) 199 return ExitStatusOK 200 } 201 202 return ExitStatusOther 203 204 } 205 206 func initInfoLog(msg string) { 207 log.Info().Str("type", "init").Msg(msg) 208 } 209 210 func logVersionInfo() { 211 initInfoLog("Version: " + BuildVersion) 212 initInfoLog("Build time: " + BuildTime) 213 initInfoLog("Branch: " + BuildBranch) 214 initInfoLog("Commit: " + BuildCommit) 215 initInfoLog("Utils version:" + UtilsVersion) 216 initInfoLog("OCP rules version:" + OCPRulesVersion) 217 } 218 219 const helpMessageTemplate = ` 220 Service to provide content for OCP rules 221 222 Usage: 223 224 %+v [command] 225 226 The commands are: 227 228 <EMPTY> starts content service 229 start-service starts content service 230 help prints help 231 print-help prints help 232 print-config prints current configuration set by files & env variables 233 print-groups prints current groups configuration 234 print-rules prints current parsed rules 235 print-parse-status prints information about all rules that have been parsed 236 print-version-info prints version info 237 238 ` 239 240 func printHelp() ExitCode { 241 fmt.Printf(helpMessageTemplate, os.Args[0]) 242 return ExitStatusOK 243 } 244 245 func printConfig(config conf.ConfigStruct) ExitCode { 246 configBytes, err := json.MarshalIndent(config, "", " ") 247 248 if err != nil { 249 log.Error().Err(err) 250 return ExitStatusOther 251 } 252 253 fmt.Println(string(configBytes)) 254 255 return ExitStatusOK 256 } 257 258 func main() { 259 err := conf.LoadConfiguration(defaultConfigFilename) 260 if err != nil { 261 panic(err) 262 } 263 264 err = logger.InitZerolog( 265 conf.GetLoggingConfiguration(), 266 conf.GetCloudWatchConfiguration(), 267 conf.GetSentryLoggingConfiguration(), 268 conf.GetKafkaZerologConfiguration(), 269 ) 270 if err != nil { 271 panic(err) 272 } 273 274 command := "start-service" 275 276 if len(os.Args) >= 2 { 277 command = strings.ToLower(strings.TrimSpace(os.Args[1])) 278 } 279 280 os.Exit(int(handleCommand(command))) 281 } 282 283 func handleCommand(command string) ExitCode { 284 switch command { 285 case "start-service": 286 logVersionInfo() 287 288 errCode := startService() 289 if errCode != ExitStatusOK { 290 return errCode 291 } 292 return ExitStatusOK 293 case "help", "print-help": 294 return printHelp() 295 case "print-config": 296 return printConfig(conf.Config) 297 case "print-version-info": 298 return printVersionInfo() 299 case "print-groups": 300 return printGroups() 301 case "print-rules": 302 return printRules() 303 case "print-parse-status": 304 return printParseStatus() 305 default: 306 fmt.Printf("\nCommand '%v' not found\n", command) 307 return printHelp() 308 } 309 }