github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/inspector/server.go (about) 1 package inspector 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "net/http" 9 10 "github.com/apprenda/kismatic/pkg/inspector/check" 11 "github.com/apprenda/kismatic/pkg/inspector/rule" 12 ) 13 14 // Server supports the execution of inspector rules from a remote node 15 type Server struct { 16 // The Port the server will listen on 17 Port int 18 // NodeFacts are the facts that apply to the node where the server is running 19 NodeFacts []string 20 // RulesEngine for running inspector rules 21 rulesEngine *rule.Engine 22 } 23 24 type serverError struct { 25 Error string 26 } 27 28 var executeEndpoint = "/execute" 29 var closeEndpoint = "/close" 30 31 // NewServer returns an inspector server that has been initialized 32 // with the default rules engine 33 func NewServer(nodeFacts []string, port int, packageInstallationDisabled bool, dockerInstallationDisabled bool, disconnectedInstallation bool) (*Server, error) { 34 s := &Server{ 35 Port: port, 36 } 37 distro, err := check.DetectDistro() 38 if err != nil { 39 return nil, fmt.Errorf("error building server: %v", err) 40 } 41 s.NodeFacts = append(nodeFacts, string(distro)) 42 pkgMgr, err := check.NewPackageManager(distro) 43 if err != nil { 44 return nil, fmt.Errorf("error building server: %v", err) 45 } 46 engine := &rule.Engine{ 47 RuleCheckMapper: rule.DefaultCheckMapper{ 48 PackageManager: pkgMgr, 49 PackageInstallationDisabled: packageInstallationDisabled, 50 DockerInstallationDisabled: dockerInstallationDisabled, 51 DisconnectedInstallation: disconnectedInstallation, 52 }, 53 } 54 s.rulesEngine = engine 55 return s, nil 56 } 57 58 // Start the server 59 func (s *Server) Start() error { 60 mux := http.NewServeMux() 61 // Execute endpoint 62 mux.HandleFunc(executeEndpoint, func(w http.ResponseWriter, req *http.Request) { 63 if req.Method != http.MethodPost { 64 w.WriteHeader(http.StatusMethodNotAllowed) 65 return 66 } 67 // Decode rules 68 data, err := ioutil.ReadAll(req.Body) 69 if err != nil { 70 w.WriteHeader(http.StatusInternalServerError) 71 log.Printf("error decoding rules when processing request: %v", err) 72 return 73 } 74 defer req.Body.Close() 75 rules, err := rule.UnmarshalRulesJSON(data) 76 if err != nil { 77 w.WriteHeader(http.StatusBadRequest) 78 log.Printf("error unmarshaling rules from JSON: %v", err) 79 return 80 } 81 // Run the rules that we received 82 results, err := s.rulesEngine.ExecuteRules(rules, s.NodeFacts) 83 if err != nil { 84 err = json.NewEncoder(w).Encode(serverError{Error: err.Error()}) 85 if err != nil { 86 log.Printf("error writing server response: %v\n", err) 87 } 88 w.WriteHeader(http.StatusInternalServerError) 89 return 90 } 91 err = json.NewEncoder(w).Encode(results) 92 if err != nil { 93 log.Printf("error writing server response: %v\n", err) 94 w.WriteHeader(http.StatusInternalServerError) 95 } 96 }) 97 // Close endpoint 98 mux.HandleFunc(closeEndpoint, func(w http.ResponseWriter, req *http.Request) { 99 err := s.rulesEngine.CloseChecks() 100 if err != nil { 101 log.Printf("error closing checks: %v", err) 102 w.WriteHeader(http.StatusInternalServerError) 103 } 104 w.WriteHeader(http.StatusOK) 105 }) 106 return http.ListenAndServe(fmt.Sprintf(":%d", s.Port), mux) 107 }